Skip to content
This repository was archived by the owner on Dec 16, 2020. It is now read-only.

Commit d7a768b

Browse files
committed
Working protoype
1 parent aea4bf7 commit d7a768b

File tree

8 files changed

+110
-46
lines changed

8 files changed

+110
-46
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@ build/
2121
*/build/
2222
out/
2323

24+
# Module artifacts
25+
os.txt
26+
2427
# Go best practices dictate that libraries should not include the vendor directory
2528
vendor
2629

README.md

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -39,16 +39,26 @@ This repo provides a Gruntwork IaC Package and has the following folder structur
3939
all the security best practices.
4040
* [modules](/modules): This folder contains the main implementation code for this Module, broken down into multiple
4141
standalone Submodules.
42+
43+
The primary module is:
44+
45+
* [k8s-tiller](/modules/k8s-tiller): Deploy Tiller with all the security features turned on. This includes using
46+
`Secrets` for storing state and enabling TLS verification.
47+
48+
The deployed Tiller requires TLS certificate key pairs to operate. Additionally, clients will each need to their
49+
own TLS certificate key pairs to authenticate to the deployed Tiller instance. This is based on [kubergrunt model of
50+
deploying helm](https://github.com/gruntwork-io/kubergrunt/blob/master/HELM_GUIDE.md).
51+
52+
There are also several supporting modules that help with setting up the deployment:
53+
54+
* [k8s-namespace](/modules/k8s-namespace): Provision a Kubernetes `Namespace` with a default set of RBAC roles.
55+
* [k8s-namespace-roles](/modules/k8s-namespace-roles): Provision a default set of RBAC roles to use in a `Namespace`.
56+
* [k8s-service-account](/modules/k8s-service-account): Provision a Kubernetes `ServiceAccount`.
57+
4258
* [examples](/examples): This folder contains examples of how to use the Submodules. The [example root
4359
README](/examples/README.md) provides a quickstart guide on how to use the Submodules in this Module.
4460
* [test](/test): Automated tests for the Submodules and examples.
4561

46-
The following submodules are available in this module:
47-
48-
- [k8s-namespace](/modules/k8s-namespace): Provision a Kubernetes `Namespace` with a default set of RBAC roles.
49-
- [k8s-namespace-roles](/modules/k8s-namespace-roles): Provision a default set of RBAC roles to use in a `Namespace`.
50-
- [k8s-service-account](/modules/k8s-service-account): Provision a Kubernetes `ServiceAccount`.
51-
5262

5363
## What is Kubernetes?
5464

examples/k8s-tiller-minikube/README.md

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -204,16 +204,21 @@ to implementing the functionalities using pure Terraform providers. This approac
204204
`destroy`.
205205

206206
That said, we decided to use this approach because of limitations in the existing providers to implement the
207-
functionalities here in pure Terraform code:
207+
functionalities here in pure Terraform code.
208+
209+
`kubergrunt` fulfills the role of generating and managing TLS certificate key pairs using Kubernetes `Secrets` as a
210+
database. This allows us to deploy Tiller with TLS verification enabled. We could instead use the `tls` and `kubernetes`
211+
providers in Terraform, but this has a few drawbacks:
208212

209-
- The Helm provider does not have [a resource that manages
210-
Tiller](https://github.com/terraform-providers/terraform-provider-helm/issues/134).
211213
- The [TLS provider](https://www.terraform.io/docs/providers/tls/index.html) stores the certificate key pairs in plain
212214
text into the Terraform state.
213215
- The Kubernetes Secret resource in the provider [also stores the value in plain text in the Terraform
214216
state](https://www.terraform.io/docs/providers/kubernetes/r/secret.html).
215217
- The grant and configure workflows are better suited as CLI tools than in Terraform.
216218

217-
Note that [we intend to implement a pure Terraform version of this when the Helm provider is
218-
updated](https://github.com/gruntwork-io/terraform-kubernetes-helm/issues/13), but we plan to continue to maintain the
219+
`kubergrunt` works around this by generating the TLS certs and storing them in Kubernetes `Secrets` directly. In this
220+
way, the generated TLS certs never leak into the Terraform state as they are referenced by name when deploying Tiller as
221+
opposed to by value.
222+
223+
Note that we intend to implement a pure Terraform version of this functionality, but we plan to continue to maintain the
219224
`kubergrunt` approach for folks who are wary of leaking secrets into Terraform state.

main.tf

Lines changed: 54 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ provider "kubernetes" {
2222
module "tiller_namespace" {
2323
# When using these modules in your own templates, you will need to use a Git URL with a ref attribute that pins you
2424
# to a specific version of the modules, such as the following example:
25-
# source = "git::[email protected]:gruntwork-io/terraform-kubernetes-helm.git//modules/k8s-namespace?ref=v0.1.0"
25+
# source = "git::[email protected]:gruntwork-io/terraform-kubernetes-helm.git//modules/k8s-namespace?ref=v0.3.0"
2626
source = "./modules/k8s-namespace"
2727

2828
name = "${var.tiller_namespace}"
@@ -31,7 +31,7 @@ module "tiller_namespace" {
3131
module "resource_namespace" {
3232
# When using these modules in your own templates, you will need to use a Git URL with a ref attribute that pins you
3333
# to a specific version of the modules, such as the following example:
34-
# source = "git::[email protected]:gruntwork-io/terraform-kubernetes-helm.git//modules/k8s-namespace?ref=v0.1.0"
34+
# source = "git::[email protected]:gruntwork-io/terraform-kubernetes-helm.git//modules/k8s-namespace?ref=v0.3.0"
3535
source = "./modules/k8s-namespace"
3636

3737
name = "${var.resource_namespace}"
@@ -40,7 +40,7 @@ module "resource_namespace" {
4040
module "tiller_service_account" {
4141
# When using these modules in your own templates, you will need to use a Git URL with a ref attribute that pins you
4242
# to a specific version of the modules, such as the following example:
43-
# source = "git::[email protected]:gruntwork-io/terraform-kubernetes-helm.git//modules/k8s-service-account?ref=v0.1.0"
43+
# source = "git::[email protected]:gruntwork-io/terraform-kubernetes-helm.git//modules/k8s-service-account?ref=v0.3.0"
4444
source = "./modules/k8s-service-account"
4545

4646
name = "${var.service_account_name}"
@@ -64,24 +64,31 @@ module "tiller_service_account" {
6464
}
6565

6666
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
67-
# DEPLOY TILLER
67+
# GENERATE TLS CERTIFICATES FOR USE WITH TILLER
68+
# This will use kubergrunt to generate TLS certificates, and upload them as Kubernetes Secrets that can then be used by
69+
# Tiller.
6870
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
6971

70-
resource "null_resource" "tiller_tls_ca_certs" {
71-
provisioner "local-exec" {
72-
command = "kubergrunt tls gen --ca --namespace kube-system --secret-name ${local.tls_ca_secret_name} --secret-label gruntwork.io/tiller-namespace=${var.tiller_namespace} --secret-label gruntwork.io/tiller-credentials=true --secret-label gruntwork.io/tiller-credentials-type=ca --tls-subject-json '${jsonencode(var.tls_subject)}' --tls-private-key-algorithm ${var.private_key_algorithm} ${local.tls_algorithm_config} ${local.kubectl_config_options}"
73-
}
74-
}
75-
7672
resource "null_resource" "tiller_tls_certs" {
7773
provisioner "local-exec" {
78-
command = "kubergrunt tls gen --namespace ${module.tiller_namespace.name} --ca-secret-name ${local.tls_ca_secret_name} --ca-namespace kube-system --secret-name ${local.tls_secret_name} --secret-label gruntwork.io/tiller-namespace=${var.tiller_namespace} --secret-label gruntwork.io/tiller-credentials=true --secret-label gruntwork.io/tiller-credentials-type=server --tls-subject-json '${jsonencode(var.tls_subject)}' --tls-private-key-algorithm ${var.private_key_algorithm} ${local.tls_algorithm_config} ${local.kubectl_config_options}"
79-
}
74+
command = <<-EOF
75+
# Generate CA TLS certs
76+
kubergrunt tls gen --ca --namespace kube-system --secret-name ${local.tls_ca_secret_name} --secret-label gruntwork.io/tiller-namespace=${var.tiller_namespace} --secret-label gruntwork.io/tiller-credentials=true --secret-label gruntwork.io/tiller-credentials-type=ca --tls-subject-json '${jsonencode(var.tls_subject)}' --tls-private-key-algorithm ${var.private_key_algorithm} ${local.tls_algorithm_config} ${local.kubectl_config_options}
8077
81-
depends_on = ["null_resource.tiller_tls_ca_certs"]
78+
# Then use that CA to generate server TLS certs
79+
kubergrunt tls gen --namespace ${module.tiller_namespace.name} --ca-secret-name ${local.tls_ca_secret_name} --ca-namespace kube-system --secret-name ${local.tls_secret_name} --secret-label gruntwork.io/tiller-namespace=${var.tiller_namespace} --secret-label gruntwork.io/tiller-credentials=true --secret-label gruntwork.io/tiller-credentials-type=server --tls-subject-json '${jsonencode(var.tls_subject)}' --tls-private-key-algorithm ${var.private_key_algorithm} ${local.tls_algorithm_config} ${local.kubectl_config_options}
80+
EOF
81+
}
8282
}
8383

84+
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
85+
# DEPLOY TILLER
86+
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
87+
8488
module "tiller" {
89+
# When using these modules in your own templates, you will need to use a Git URL with a ref attribute that pins you
90+
# to a specific version of the modules, such as the following example:
91+
# source = "git::[email protected]:gruntwork-io/terraform-kubernetes-helm.git//modules/k8s-tiller?ref=v0.3.0"
8592
source = "./modules/k8s-tiller"
8693

8794
tiller_service_account_name = "${module.tiller_service_account.name}"
@@ -93,22 +100,50 @@ module "tiller" {
93100
# Kubergrunt will store the private key under tls.pem
94101
tiller_tls_key_file_name = "tls.pem"
95102

96-
dependencies = [
97-
"${null_resource.tiller_tls_ca_certs.id}",
98-
"${null_resource.tiller_tls_certs.id}",
99-
]
103+
dependencies = ["${null_resource.tiller_tls_certs.id}"]
100104
}
101105

102-
locals {
103-
helm_home_with_default = "${var.helm_home == "" ? pathexpand("~/.helm") : var.helm_home}"
106+
# We use kubergrunt to wait for Tiller to be deployed. Any resources that depend on this can assume Tiller is
107+
# successfully deployed and up at that point.
108+
resource "null_resource" "wait_for_tiller" {
109+
provisioner "local-exec" {
110+
command = "kubergrunt helm wait-for-tiller --tiller-namespace ${module.tiller_namespace.name} --tiller-deployment-name ${module.tiller.deployment_name} --expected-tiller-version ${var.tiller_version}"
111+
}
112+
}
113+
114+
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
115+
# CONFIGURE OPERATOR HELM CLIENT
116+
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
117+
118+
resource "null_resource" "grant_and_configure_helm" {
119+
count = "${var.configure_helm}"
120+
121+
provisioner "local-exec" {
122+
command = <<-EOF
123+
kubergrunt helm grant --tiller-namespace ${module.tiller_namespace.name} ${local.kubectl_config_options} --tls-subject-json '${jsonencode(var.client_tls_subject)}' ${local.configure_args}
124+
125+
kubergrunt helm configure --helm-home ${local.helm_home_with_default} --tiller-namespace ${module.tiller_namespace.name} --resource-namespace ${module.resource_namespace.name} ${local.kubectl_config_options} ${local.configure_args}
126+
EOF
127+
}
104128

129+
depends_on = ["null_resource.wait_for_tiller"]
130+
}
131+
132+
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
133+
# COMPUTATIONS
134+
# These locals compute various useful information used throughout this Terraform module.
135+
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
136+
137+
locals {
105138
kubectl_config_options = "${var.kubectl_config_context_name != "" ? "--kubectl-context-name ${var.kubectl_config_context_name}" : ""} ${var.kubectl_config_path != "" ? "--kubeconfig ${var.kubectl_config_path}" : ""}"
106139

107140
tls_ca_secret_name = "${var.tiller_namespace}-namespace-tiller-ca-certs"
108141
tls_secret_name = "tiller-certs"
109142

110143
tls_algorithm_config = "${var.private_key_algorithm == "ECDSA" ? "--tls-private-key-ecdsa-curve ${var.private_key_ecdsa_curve}" : "--tls-private-key-rsa-bits ${var.private_key_rsa_bits}"}"
111144

145+
helm_home_with_default = "${var.helm_home == "" ? pathexpand("~/.helm") : var.helm_home}"
146+
112147
configure_args = "${
113148
var.helm_client_rbac_user != "" ? "--rbac-user ${var.helm_client_rbac_user}"
114149
: var.helm_client_rbac_group != "" ? "--rbac-group ${var.helm_client_rbac_group}"

modules/k8s-tiller/main.tf

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ resource "null_resource" "dependency_getter" {
1515
# Adapted from Tiller installer in helm client. See:
1616
# https://github.com/helm/helm/blob/master/cmd/helm/installer/install.go#L200
1717
resource "kubernetes_deployment" "tiller" {
18+
depends_on = ["null_resource.dependency_getter"]
19+
1820
metadata {
1921
namespace = "${var.namespace}"
2022
name = "${var.deployment_name}"
@@ -173,14 +175,14 @@ resource "kubernetes_deployment" "tiller" {
173175
# end spec
174176
}
175177

176-
depends_on = ["null_resource.dependency_getter"]
177-
178178
# end deployment
179179
}
180180

181181
# Adapted from Tiller installer in helm client. See:
182182
# https://github.com/helm/helm/blob/master/cmd/helm/installer/install.go#L332
183183
resource "kubernetes_service" "tiller" {
184+
depends_on = ["null_resource.dependency_getter"]
185+
184186
metadata {
185187
namespace = "${var.namespace}"
186188
name = "${var.service_name}"
@@ -211,8 +213,6 @@ resource "kubernetes_service" "tiller" {
211213
deployment = "${var.deployment_name}"
212214
}
213215
}
214-
215-
depends_on = ["null_resource.dependency_getter"]
216216
}
217217

218218
# Global constants

modules/k8s-tiller/outputs.tf

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
output "deployment_name" {
2+
description = "The name of the Deployment resource that manages the Tiller Pods."
3+
value = "${kubernetes_deployment.tiller.metadata.0.name}"
4+
}
5+
6+
output "service_name" {
7+
description = "The name of the Service resource that fronts the Tiller Pods."
8+
value = "${kubernetes_service.tiller.metadata.0.name}"
9+
}

outputs.tf

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
output "tiller_namespace" {
2+
description = "The name of the namespace that houses Tiller."
3+
value = "${module.tiller_namespace.name}"
4+
}
5+
6+
output "resource_namespace" {
7+
description = "The name of the namespace where Tiller will deploy resources into."
8+
value = "${module.resource_namespace.name}"
9+
}

variables.tf

Lines changed: 5 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -70,18 +70,6 @@ variable "private_key_rsa_bits" {
7070
default = "2048"
7171
}
7272

73-
# Undeploy options
74-
75-
variable "force_undeploy" {
76-
description = "If true, will remove the Tiller server resources even if there are releases deployed."
77-
default = false
78-
}
79-
80-
variable "undeploy_releases" {
81-
description = "If true, will delete deployed releases from the Tiller instance before undeploying Tiller."
82-
default = false
83-
}
84-
8573
# Kubectl options
8674

8775
variable "kubectl_config_context_name" {
@@ -96,6 +84,11 @@ variable "kubectl_config_path" {
9684

9785
# Helm client config options
9886

87+
variable "configure_helm" {
88+
description = "Whether or not to configure the local helm client to authenticate to the deployed Tiller instance."
89+
default = true
90+
}
91+
9992
variable "helm_home" {
10093
description = "The path to the home directory for helm that you wish to use for this deployment."
10194
default = ""

0 commit comments

Comments
 (0)