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

k8s-tiller module #9

Closed
wants to merge 9 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,14 @@ defaults: &defaults
environment:
GRUNTWORK_INSTALLER_VERSION: v0.0.21
TERRATEST_LOG_PARSER_VERSION: v0.13.13
KUBERGRUNT_VERSION: v0.1.4
KUBERGRUNT_VERSION: v0.1.5
MODULE_CI_VERSION: v0.13.3
TERRAFORM_VERSION: 0.11.8
TERRAGRUNT_VERSION: NONE
PACKER_VERSION: NONE
GOLANG_VERSION: 1.11.2
K8S_VERSION: v1.10.0 # Same as EKS
HELM_VERSION: v2.12.2
KUBECONFIG: /home/circleci/.kube/config
MINIKUBE_VERSION: v0.28.2 # See https://github.com/kubernetes/minikube/issues/2704
MINIKUBE_WANTUPDATENOTIFICATION: "false"
Expand All @@ -29,6 +30,12 @@ setup_minikube: &setup_minikube
mkdir -p ${HOME}/.kube
touch ${HOME}/.kube/config

# install helm
curl -Lo helm.tar.gz https://storage.googleapis.com/kubernetes-helm/helm-${HELM_VERSION}-linux-amd64.tar.gz
tar -xvf helm.tar.gz
chmod +x linux-amd64/helm
sudo mv linux-amd64/helm /usr/local/bin/

# Install minikube
curl -Lo minikube https://github.com/kubernetes/minikube/releases/download/${MINIKUBE_VERSION}/minikube-linux-amd64
chmod +x minikube
Expand Down
18 changes: 10 additions & 8 deletions examples/k8s-namespace-with-service-account/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,11 @@ module "service_account_access_all" {
# source = "git::git@github.com:gruntwork-io/terraform-kubernetes-helm.git//modules/k8s-service-account?ref=v0.0.1"
source = "../../modules/k8s-service-account"

name = "${var.name}-admin"
namespace = "${module.namespace.name}"
num_rbac_roles = 1
rbac_roles = ["${module.namespace.rbac_access_all_role}"]
name = "${var.name}-admin"
namespace = "${module.namespace.name}"
num_rbac_roles = 1
rbac_roles = ["${module.namespace.rbac_access_all_role}"]
rbac_role_namespaces = ["${module.namespace.name}"]

# How to tag the service account with a label
labels = {
Expand All @@ -54,10 +55,11 @@ module "service_account_access_read_only" {
# source = "git::git@github.com:gruntwork-io/terraform-kubernetes-helm.git//modules/k8s-service-account?ref=v0.0.1"
source = "../../modules/k8s-service-account"

name = "${var.name}-read-only"
namespace = "${module.namespace.name}"
num_rbac_roles = 1
rbac_roles = ["${module.namespace.rbac_access_read_only_role}"]
name = "${var.name}-read-only"
namespace = "${module.namespace.name}"
num_rbac_roles = 1
rbac_roles = ["${module.namespace.rbac_access_read_only_role}"]
rbac_role_namespaces = ["${module.namespace.name}"]

# How to tag the service account with a label
labels = {
Expand Down
28 changes: 28 additions & 0 deletions examples/k8s-tiller/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# K8S Tiller

This folder shows an example of how to deploy Tiller (the server component of Helm) on your Kubernetes cluster following
the best practices for securing access.

This guide requires a Kubernetes instance. You can either use:

- [minikube](https://kubernetes.io/docs/tasks/tools/install-minikube/)
- [Kubernetes on Docker for Mac](https://docs.docker.com/docker-for-mac/kubernetes/)
- EKS
- GKE
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Link to our modules?



## How do you run this example?

In addition to Terraform, this example depends on modules that use the
[`kubergrunt`](https://github.com/gruntwork-io/kubergrunt) utility under the hood.

To run this example, apply the Terraform templates:

1. Install [Terraform](https://www.terraform.io/), minimum version: `0.9.7`.
1. Install [kubectl](https://kubernetes.io/docs/tasks/tools/install-kubectl/).
1. Install [helm client](https://docs.helm.sh/using_helm/#install-helm)
1. Install [kubergrunt](https://github.com/gruntwork-io/kubergrunt)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wow, that's a lot of stuff to install. I think I've asked before, but does it make sense to embed kubectl or helm client in kubergrunt (or call the APIs they are using directly)? Or do their versions/APIs change so often that we'd never be able to keep up?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I haven't looked into this yet for helm, but for kubectl, we can't embed it because a lot of the logic is baked into the command (package main) as opposed to a library.

That said, based on what I know, I think it is safe to assume that everyone will have kubectl installed if they are doing anything related to Kubernetes. You lose A LOT when you don't have that, so that one is more or less a moot operation.

I think the helm client might be avoidable, but I will have to look into that more. I would probably file that away as a "nice to have" though. I filed gruntwork-io/kubergrunt#13 so we don't forget this thought.

1. Open `variables.tf`, set the environment variables specified at the top of the file, and fill in any other variables
that don't have a default.
1. Run `terraform init`.
1. Run `terraform apply`.
41 changes: 28 additions & 13 deletions examples/secure-helm/main.tf → examples/k8s-tiller/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@ provider "kubernetes" {
}

# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# CREATE THE HELM SERVER
# DEPLOY TILLER
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

module "helm_server" {
module "tiller" {
# When using these modules in your own templates, you will need to use a Git URL with a ref attribute that pins you
# to a specific version of the modules, such as the following example:
# source = "git::git@github.com:gruntwork-io/terraform-kubernetes-helm.git//modules/k8s-tiller?ref=v0.1.0"
Expand All @@ -23,6 +23,25 @@ module "helm_server" {
resource_namespace = "${module.resource_namespace.name}"
service_account = "${module.tiller_service_account.name}"
tls_subject = "${var.tls_subject}"

grant_access_to_rbac_users = ["${var.grant_access_to_rbac_users}"]
grant_access_to_rbac_groups = ["${var.grant_access_to_rbac_groups}"]
grant_access_to_rbac_service_accounts = ["${var.grant_access_to_rbac_service_accounts}"]
helm_client_rbac_user = "${var.helm_client_rbac_user}"
helm_client_rbac_group = "${var.helm_client_rbac_group}"
helm_client_rbac_service_account = "${var.helm_client_rbac_service_account}"

# We force remove Tiller here for testing purposes when you run destroy, but in production, you may want more conservative options.
force_undeploy = true
undeploy_releases = true

# We specify these as dependencies for this module, because we can't destroy Tiller if the roles are removed (and thus
# we lose access!)
dependencies = [
"${module.tiller_namespace.rbac_access_all_role}",
"${module.resource_namespace.rbac_access_all_role}",
"${module.tiller_service_account.depended_on}",
]
}

# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Expand All @@ -35,9 +54,7 @@ module "tiller_namespace" {
# source = "git::git@github.com:gruntwork-io/terraform-kubernetes-helm.git//modules/k8s-namespace?ref=v0.1.0"
source = "../../modules/k8s-namespace"

kubectl_config_context_name = "${var.kubectl_config_context_name}"
kubectl_config_path = "${var.kubectl_config_path}"
name = "${var.tiller_namespace}"
name = "${var.tiller_namespace}"
}

module "resource_namespace" {
Expand All @@ -46,9 +63,7 @@ module "resource_namespace" {
# source = "git::git@github.com:gruntwork-io/terraform-kubernetes-helm.git//modules/k8s-namespace?ref=v0.1.0"
source = "../../modules/k8s-namespace"

kubectl_config_context_name = "${var.kubectl_config_context_name}"
kubectl_config_path = "${var.kubectl_config_path}"
name = "${var.resource_namespace}"
name = "${var.resource_namespace}"
}

module "tiller_service_account" {
Expand All @@ -57,11 +72,11 @@ module "tiller_service_account" {
# source = "git::git@github.com:gruntwork-io/terraform-kubernetes-helm.git//modules/k8s-service-account?ref=v0.1.0"
source = "../../modules/k8s-service-account"

kubectl_config_context_name = "${var.kubectl_config_context_name}"
kubectl_config_path = "${var.kubectl_config_path}"
name = "${var.service_account_name}"
namespace = "${module.tiller_namespace.name}"
rbac_roles = ["${module.tiller_namespace.rbac_access_all_role}", "${module.resource_namespace.rbac_access_all_role}"]
name = "${var.service_account_name}"
namespace = "${module.tiller_namespace.name}"
num_rbac_roles = 2
rbac_roles = ["${module.tiller_namespace.rbac_access_all_role}", "${module.resource_namespace.rbac_access_all_role}"]
rbac_role_namespaces = ["${module.tiller_namespace.name}", "${module.resource_namespace.name}"]

labels = {
app = "tiller"
Expand Down
14 changes: 14 additions & 0 deletions examples/k8s-tiller/outputs.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
output "resource_namespace_name" {
description = "Name of the created resource namespace"
value = "${module.resource_namespace.name}"
}

output "resource_namespace_rbac_access_all_role" {
description = "The name of the RBAC role that grants admin level permissions on the resource namespace."
value = "${module.resource_namespace.rbac_access_all_role}"
}

output "resource_namespace_rbac_access_read_only_role" {
description = "The name of the RBAC role that grants read only permissions on the resource namespace."
value = "${module.resource_namespace.rbac_access_read_only_role}"
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,3 @@
# ---------------------------------------------------------------------------------------------------------------------
# ENVIRONMENT VARIABLES
# Define these secrets as environment variables
# ---------------------------------------------------------------------------------------------------------------------

# AWS_ACCESS_KEY_ID
# AWS_SECRET_ACCESS_KEY

# ---------------------------------------------------------------------------------------------------------------------
# MODULE PARAMETERS
# These variables are expected to be passed in by the operator
Expand Down Expand Up @@ -36,6 +28,11 @@ variable "tls_subject" {
# - country
}

# ---------------------------------------------------------------------------------------------------------------------
# OPTIONAL MODULE PARAMETERS
# These variables have reasonable defaults, but can be overridden.
# ---------------------------------------------------------------------------------------------------------------------

variable "kubectl_config_context_name" {
description = "The config context to use when authenticating to the Kubernetes cluster. If empty, defaults to the current context specified in the kubeconfig file."
default = ""
Expand All @@ -45,3 +42,41 @@ variable "kubectl_config_path" {
description = "The path to the config file to use for kubectl. If empty, defaults to $HOME/.kube/config"
default = "~/.kube/config"
}

variable "grant_access_to_rbac_users" {
description = "The list of RBAC Users that should be granted access to the Tiller instance."
type = "list"
default = []
}

variable "grant_access_to_rbac_groups" {
description = "The list of RBAC Groups that should be granted access to the Tiller instance."
type = "list"
default = []
}

variable "grant_access_to_rbac_service_accounts" {
description = "The list of ServiceAccounts that should be granted access to the Tiller instance. The ServiceAccount should be encoded as NAMESPACE/NAME."
type = "list"
default = []
}

variable "helm_home" {
description = "The path to the home directory for helm that you wish to use for this deployment."
default = ""
}

variable "helm_client_rbac_user" {
description = "If set, will setup the local helm client to authenticate using this RBAC user. The RBAC user must be in the grant_access_to_rbac_users list."
default = ""
}

variable "helm_client_rbac_group" {
description = "If set, will setup the local helm client to authenticate using this RBAC group. The RBAC group must be in the grant_access_to_rbac_groups list."
default = ""
}

variable "helm_client_rbac_service_account" {
description = "If set, will setup the local helm client to authenticate using this ServiceAccount. The ServiceAccount should be encoded as NAMESPACE/NAME. The ServiceAccount must be in the grant_access_to_rbac_service_accounts list."
default = ""
}
9 changes: 0 additions & 9 deletions examples/secure-helm/README.md

This file was deleted.

34 changes: 31 additions & 3 deletions modules/k8s-namespace/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,18 @@ terraform {
required_version = "~> 0.9"
}

# ---------------------------------------------------------------------------------------------------------------------
# SET MODULE DEPENDENCY RESOURCE
# This works around a terraform limitation where we can not specify module dependencies natively.
# See https://github.com/hashicorp/terraform/issues/1178 for more discussion.
# ---------------------------------------------------------------------------------------------------------------------
Copy link
Contributor Author

@yorinasub17 yorinasub17 Jan 31, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@rileykarson Ok I found this pattern that was posted in December on module dependencies and it appears to be working well. I think this can be used to now chain the namespace module to the role binding.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you explain what this is meant to be used for? That is, what are you depending on?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The main issue with GKE is that the default permissions are not enough to create additional RBAC roles. So you have to first promote the user to a cluster admin, and then you can proceed to create these roles. So in terraform, we need to make sure we apply these rules after the cluster admin role binding is created.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Specifically, your identity needs to have a superset of the permissions of a role to create that role. See https://cloud.google.com/kubernetes-engine/docs/how-to/role-based-access-control#defining_permissions_in_a_role


resource "null_resource" "dependency_getter" {
provisioner "local-exec" {
command = "echo ${length(var.dependencies)}"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does echo exist on Windows?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On Powershell yes. I have verified this. This does not exist on CMD though so not the most portable, but probably good enough based on prior conversations.

}
}

# ---------------------------------------------------------------------------------------------------------------------
# CREATE THE NAMESPACE
# ---------------------------------------------------------------------------------------------------------------------
Expand All @@ -22,6 +34,8 @@ resource "kubernetes_namespace" "namespace" {
labels = "${var.labels}"
annotations = "${var.annotations}"
}

depends_on = ["null_resource.dependency_getter"]
}

# ---------------------------------------------------------------------------------------------------------------------
Expand All @@ -34,7 +48,7 @@ resource "kubernetes_namespace" "namespace" {
resource "kubernetes_role" "rbac_role_access_all" {
metadata {
name = "${var.name}-access-all"
namespace = "${var.name}"
namespace = "${kubernetes_namespace.namespace.id}"
labels = "${var.labels}"
annotations = "${var.annotations}"
}
Expand All @@ -48,8 +62,10 @@ resource "kubernetes_role" "rbac_role_access_all" {

resource "kubernetes_role" "rbac_role_access_read_only" {
metadata {
name = "${var.name}-access-read-only"
namespace = "${var.name}"
name = "${var.name}-access-read-only"
namespace = "${kubernetes_namespace.namespace.id}"
labels = "${var.labels}"
annotations = "${var.annotations}"
}

rule {
Expand All @@ -58,3 +74,15 @@ resource "kubernetes_role" "rbac_role_access_read_only" {
verbs = ["get", "list", "watch"]
}
}

# ---------------------------------------------------------------------------------------------------------------------
# SET MODULE CHILD DEPENDENCY RESOURCE
# This works around a terraform limitation where we can not specify module dependencies natively.
# See https://github.com/hashicorp/terraform/issues/1178 for more discussion.
# ---------------------------------------------------------------------------------------------------------------------

# List resource(s) that will be constructed last within the module, so that we can create an output that can be used to
# chain dependencies.
resource "null_resource" "dependency_setter" {
depends_on = ["kubernetes_role.rbac_role_access_read_only", "kubernetes_role.rbac_role_access_all"]
}
5 changes: 5 additions & 0 deletions modules/k8s-namespace/outputs.tf
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,8 @@ output "rbac_access_read_only_role" {
description = "The name of the RBAC role that grants read only permissions on the namespace."
value = "${kubernetes_role.rbac_role_access_read_only.metadata.0.name}"
}

output "depended_on" {
description = "This output can be used to depend on the resources in this module."
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Example use case?

value = "${null_resource.dependency_setter.id}"
}
12 changes: 12 additions & 0 deletions modules/k8s-namespace/variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,15 @@ variable "annotations" {
type = "map"
default = {}
}

# ---------------------------------------------------------------------------------------------------------------------
# MODULE DEPENDENCIES
# Workaround Terraform limitation where there is no module depends_on.
# See https://github.com/hashicorp/terraform/issues/1178 for more details.
# ---------------------------------------------------------------------------------------------------------------------

variable "dependencies" {
description = "Create a dependency between the resources in this module to the interpolated values in this list (and thus the source resources). In other words, the resources in this module will now depend on the resources backing the values in this list such that those resources need to be created before the resources in this module, and the resources in this module need to be destroyed before the resources in the list."
type = "list"
default = []
}
Loading