From 23c005e5ef6107a52af37e6c17e9d572ebc3d81d Mon Sep 17 00:00:00 2001 From: Wolodja Wentland Date: Wed, 11 Mar 2020 11:26:06 +0000 Subject: [PATCH] Add EKS Secret envelope encryption support (#772) This adds support for configuring EKS clusters that utilise envelope encryption for Secrets: - https://aws.amazon.com/about-aws/whats-new/2020/03/amazon-eks-adds-envelope-encryption-for-secrets-with-aws-kms/ - https://aws.amazon.com/blogs/containers/using-eks-encryption-provider-support-for-defense-in-depth/ --- CHANGELOG.md | 1 + README.md | 3 +- cluster.tf | 11 +++ examples/secrets_encryption/main.tf | 118 +++++++++++++++++++++++ examples/secrets_encryption/outputs.tf | 24 +++++ examples/secrets_encryption/variables.tf | 52 ++++++++++ variables.tf | 9 ++ versions.tf | 2 +- 8 files changed, 218 insertions(+), 2 deletions(-) create mode 100644 examples/secrets_encryption/main.tf create mode 100644 examples/secrets_encryption/outputs.tf create mode 100644 examples/secrets_encryption/variables.tf diff --git a/CHANGELOG.md b/CHANGELOG.md index 13f79d2f24..86cfb3dd72 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ project adheres to [Semantic Versioning](http://semver.org/). - Add support for ASG max instance lifetime (by @sidprak) - Add `default_cooldown` and `health_check_grace_period` options to workers ASG (by @ArieLevs) - Fix support for ASG max instance lifetime for workers (by @barryib) +- Add support for envelope encryption of Secrets (by @babilen5) # History diff --git a/README.md b/README.md index 1c0a958f0e..7b2ad00b04 100644 --- a/README.md +++ b/README.md @@ -150,7 +150,7 @@ MIT Licensed. See [LICENSE](https://github.com/terraform-aws-modules/terraform-a | Name | Version | |------|---------| -| aws | >= 2.44.0 | +| aws | >= 2.52.0 | | kubernetes | >= 1.6.2 | | local | >= 1.2 | | null | >= 2.1 | @@ -166,6 +166,7 @@ MIT Licensed. See [LICENSE](https://github.com/terraform-aws-modules/terraform-a | cluster\_create\_timeout | Timeout value when creating the EKS cluster. | `string` | `"30m"` | no | | cluster\_delete\_timeout | Timeout value when deleting the EKS cluster. | `string` | `"15m"` | no | | cluster\_enabled\_log\_types | A list of the desired control plane logging to enable. For more information, see Amazon EKS Control Plane Logging documentation (https://docs.aws.amazon.com/eks/latest/userguide/control-plane-logs.html) | `list(string)` | `[]` | no | +| cluster\_encryption\_config | Configuration block with encryption configuration for the cluster. See examples/secrets\_encryption/main.tf for example format |
list(object({
provider_key_arn = string
resources = list(string)
}))
| `[]` | no | | cluster\_endpoint\_private\_access | Indicates whether or not the Amazon EKS private API server endpoint is enabled. | `bool` | `false` | no | | cluster\_endpoint\_public\_access | Indicates whether or not the Amazon EKS public API server endpoint is enabled. | `bool` | `true` | no | | cluster\_endpoint\_public\_access\_cidrs | List of CIDR blocks which can access the Amazon EKS public API server endpoint. | `list(string)` |
[
"0.0.0.0/0"
]
| no | diff --git a/cluster.tf b/cluster.tf index a327e920b6..2e0ca6862a 100644 --- a/cluster.tf +++ b/cluster.tf @@ -27,6 +27,17 @@ resource "aws_eks_cluster" "this" { delete = var.cluster_delete_timeout } + dynamic encryption_config { + for_each = toset(var.cluster_encryption_config) + + content { + provider { + key_arn = encryption_config.value["provider_key_arn"] + } + resources = encryption_config.value["resources"] + } + } + depends_on = [ aws_iam_role_policy_attachment.cluster_AmazonEKSClusterPolicy, aws_iam_role_policy_attachment.cluster_AmazonEKSServicePolicy, diff --git a/examples/secrets_encryption/main.tf b/examples/secrets_encryption/main.tf new file mode 100644 index 0000000000..67057e24b8 --- /dev/null +++ b/examples/secrets_encryption/main.tf @@ -0,0 +1,118 @@ +terraform { + required_version = ">= 0.12.0" +} + +provider "aws" { + version = ">= 2.52.0" + region = var.region +} + +provider "random" { + version = "~> 2.1" +} + +provider "local" { + version = "~> 1.2" +} + +provider "null" { + version = "~> 2.1" +} + +provider "template" { + version = "~> 2.1" +} + +data "aws_eks_cluster" "cluster" { + name = module.eks.cluster_id +} + +data "aws_eks_cluster_auth" "cluster" { + name = module.eks.cluster_id +} + +provider "kubernetes" { + host = data.aws_eks_cluster.cluster.endpoint + cluster_ca_certificate = base64decode(data.aws_eks_cluster.cluster.certificate_authority.0.data) + token = data.aws_eks_cluster_auth.cluster.token + load_config_file = false + version = "1.10" +} + +data "aws_availability_zones" "available" { +} + +locals { + cluster_name = "test-eks-${random_string.suffix.result}" +} + +resource "random_string" "suffix" { + length = 8 + special = false +} + +resource "aws_kms_key" "eks" { + description = "EKS Secret Encryption Key" +} + +module "vpc" { + source = "terraform-aws-modules/vpc/aws" + version = "2.6.0" + + name = "test-vpc" + cidr = "10.0.0.0/16" + azs = data.aws_availability_zones.available.names + private_subnets = ["10.0.1.0/24", "10.0.2.0/24", "10.0.3.0/24"] + public_subnets = ["10.0.4.0/24", "10.0.5.0/24", "10.0.6.0/24"] + enable_nat_gateway = true + single_nat_gateway = true + enable_dns_hostnames = true + + tags = { + "kubernetes.io/cluster/${local.cluster_name}" = "shared" + } + + public_subnet_tags = { + "kubernetes.io/cluster/${local.cluster_name}" = "shared" + "kubernetes.io/role/elb" = "1" + } + + private_subnet_tags = { + "kubernetes.io/cluster/${local.cluster_name}" = "shared" + "kubernetes.io/role/internal-elb" = "1" + } +} + +module "eks" { + source = "../.." + cluster_name = local.cluster_name + subnets = module.vpc.private_subnets + + cluster_encryption_config = [ + { + provider_key_arn = aws_kms_key.eks.arn + resources = ["secrets"] + } + ] + + tags = { + Environment = "test" + GithubRepo = "terraform-aws-eks" + GithubOrg = "terraform-aws-modules" + } + + vpc_id = module.vpc.vpc_id + + worker_groups = [ + { + name = "worker-group-1" + instance_type = "t2.small" + additional_userdata = "echo foo bar" + asg_desired_capacity = 2 + }, + ] + + map_roles = var.map_roles + map_users = var.map_users + map_accounts = var.map_accounts +} diff --git a/examples/secrets_encryption/outputs.tf b/examples/secrets_encryption/outputs.tf new file mode 100644 index 0000000000..51ddb024a2 --- /dev/null +++ b/examples/secrets_encryption/outputs.tf @@ -0,0 +1,24 @@ +output "cluster_endpoint" { + description = "Endpoint for EKS control plane." + value = module.eks.cluster_endpoint +} + +output "cluster_security_group_id" { + description = "Security group ids attached to the cluster control plane." + value = module.eks.cluster_security_group_id +} + +output "kubectl_config" { + description = "kubectl config as generated by the module." + value = module.eks.kubeconfig +} + +output "config_map_aws_auth" { + description = "A kubernetes configuration to authenticate to this EKS cluster." + value = module.eks.config_map_aws_auth +} + +output "region" { + description = "AWS region." + value = var.region +} diff --git a/examples/secrets_encryption/variables.tf b/examples/secrets_encryption/variables.tf new file mode 100644 index 0000000000..7085aeabd4 --- /dev/null +++ b/examples/secrets_encryption/variables.tf @@ -0,0 +1,52 @@ +variable "region" { + default = "us-west-2" +} + +variable "map_accounts" { + description = "Additional AWS account numbers to add to the aws-auth configmap." + type = list(string) + + default = [ + "777777777777", + "888888888888", + ] +} + +variable "map_roles" { + description = "Additional IAM roles to add to the aws-auth configmap." + type = list(object({ + rolearn = string + username = string + groups = list(string) + })) + + default = [ + { + rolearn = "arn:aws:iam::66666666666:role/role1" + username = "role1" + groups = ["system:masters"] + }, + ] +} + +variable "map_users" { + description = "Additional IAM users to add to the aws-auth configmap." + type = list(object({ + userarn = string + username = string + groups = list(string) + })) + + default = [ + { + userarn = "arn:aws:iam::66666666666:user/user1" + username = "user1" + groups = ["system:masters"] + }, + { + userarn = "arn:aws:iam::66666666666:user/user2" + username = "user2" + groups = ["system:masters"] + }, + ] +} diff --git a/variables.tf b/variables.tf index eac18e5eeb..0ba56ac58c 100644 --- a/variables.tf +++ b/variables.tf @@ -311,3 +311,12 @@ variable "eks_oidc_root_ca_thumbprint" { description = "Thumbprint of Root CA for EKS OIDC, Valid until 2037" default = "9e99a48a9960b14926bb7f3b02e22da2b0ab7280" } + +variable "cluster_encryption_config" { + description = "Configuration block with encryption configuration for the cluster. See examples/secrets_encryption/main.tf for example format" + type = list(object({ + provider_key_arn = string + resources = list(string) + })) + default = [] +} diff --git a/versions.tf b/versions.tf index 95fb1ef19e..f73abd331e 100644 --- a/versions.tf +++ b/versions.tf @@ -2,7 +2,7 @@ terraform { required_version = ">= 0.12.9" required_providers { - aws = ">= 2.44.0" + aws = ">= 2.52.0" local = ">= 1.2" null = ">= 2.1" template = ">= 2.1"