From 959e5330e35702666fd919d962a5847c3391c0e8 Mon Sep 17 00:00:00 2001 From: Touch Ungboriboonpisal Date: Tue, 7 May 2019 05:46:06 -0700 Subject: [PATCH] Support custom IAM roles for cluster and workers (#338) * allow specifying custom worker IAM instance profiles * allow specifying custom cluster IAM role * add doc * update changelog * use data.aws_iam_instance_profile.name --- CHANGELOG.md | 1 + README.md | 3 +++ aws_auth.tf | 4 ++-- cluster.tf | 5 ++++- data.tf | 15 +++++++++++++++ local.tf | 9 +++++++-- outputs.tf | 8 ++++---- variables.tf | 15 +++++++++++++++ workers.tf | 12 +++++++++--- workers_launch_template.tf | 4 ++-- 10 files changed, 62 insertions(+), 14 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b3612a2..41af2c1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ project adheres to [Semantic Versioning](http://semver.org/). ### Added - Added support for custom service linked role for Auto Scaling group (by @voanhduy1512) +- Added support for custom IAM roles for cluster and workers (by @erks) - Add cluster arn to outputs (by @alexsn) - Added outputs for `workers_user_data` and `workers_default_ami_id` (by @max-rocket-internet) - Added doc about spot instances (by @max-rocket-internet) diff --git a/README.md b/README.md index 4a01f89..cd3e9e1 100644 --- a/README.md +++ b/README.md @@ -118,6 +118,7 @@ MIT Licensed. See [LICENSE](https://github.com/terraform-aws-modules/terraform-a | 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 | `[]` | no | | cluster\_endpoint\_private\_access | Indicates whether or not the Amazon EKS private API server endpoint is enabled. | string | `"false"` | no | | cluster\_endpoint\_public\_access | Indicates whether or not the Amazon EKS public API server endpoint is enabled. | string | `"true"` | no | +| cluster\_iam\_role\_name | IAM role name for the cluster. Only applicable if manage_cluster_iam_resources is set to false. | string | `""` | no | | cluster\_name | Name of the EKS cluster. Also used as a prefix in names of related resources. | string | n/a | yes | | cluster\_security\_group\_id | If provided, the EKS cluster will be attached to this security group. If not given, a security group will be created with necessary ingres/egress to work with the workers and provide API access to your current IP/32. | string | `""` | no | | cluster\_version | Kubernetes version to use for the EKS cluster. | string | `"1.12"` | no | @@ -130,6 +131,8 @@ MIT Licensed. See [LICENSE](https://github.com/terraform-aws-modules/terraform-a | kubeconfig\_name | Override the default name used for items kubeconfig. | string | `""` | no | | local\_exec\_interpreter | Command to run for local-exec resources. Must be a shell-style interpreter. If you are on Windows Git Bash is a good choice. | list | `[ "/bin/sh", "-c" ]` | no | | manage\_aws\_auth | Whether to apply the aws-auth configmap file. | string | `"true"` | no | +| manage\_cluster\_iam\_resources | Whether to let the module manage cluster IAM resources. If set to false, cluster_iam_role_name must be specified. | string | `"true"` | no | +| manage\_worker\_iam\_resources | Whether to let the module manage worker IAM resources. If set to false, iam_instance_profile_name must be specified for workers. | string | `"true"` | no | | map\_accounts | Additional AWS account numbers to add to the aws-auth configmap. See examples/eks_test_fixture/variables.tf for example format. | list | `[]` | no | | map\_accounts\_count | The count of accounts in the map_accounts list. | string | `"0"` | no | | map\_roles | Additional IAM roles to add to the aws-auth configmap. See examples/eks_test_fixture/variables.tf for example format. | list | `[]` | no | diff --git a/aws_auth.tf b/aws_auth.tf index abe8d07..a86349c 100644 --- a/aws_auth.tf +++ b/aws_auth.tf @@ -39,7 +39,7 @@ data "template_file" "launch_template_worker_role_arns" { template = "${file("${path.module}/templates/worker-role.tpl")}" vars { - worker_role_arn = "arn:aws:iam::${data.aws_caller_identity.current.account_id}:role/${element(aws_iam_instance_profile.workers_launch_template.*.role, count.index)}" + worker_role_arn = "arn:aws:iam::${data.aws_caller_identity.current.account_id}:role/${element(coalescelist(aws_iam_instance_profile.workers_launch_template.*.role, data.aws_iam_instance_profile.custom_worker_group_launch_template_iam_instance_profile.*.role_name), count.index)}" } } @@ -48,7 +48,7 @@ data "template_file" "worker_role_arns" { template = "${file("${path.module}/templates/worker-role.tpl")}" vars { - worker_role_arn = "arn:aws:iam::${data.aws_caller_identity.current.account_id}:role/${element(aws_iam_instance_profile.workers.*.role, count.index)}" + worker_role_arn = "arn:aws:iam::${data.aws_caller_identity.current.account_id}:role/${element(coalescelist(aws_iam_instance_profile.workers.*.role, data.aws_iam_instance_profile.custom_worker_group_iam_instance_profile.*.role_name), count.index)}" } } diff --git a/cluster.tf b/cluster.tf index 003e591..5877c62 100644 --- a/cluster.tf +++ b/cluster.tf @@ -1,7 +1,7 @@ resource "aws_eks_cluster" "this" { name = "${var.cluster_name}" enabled_cluster_log_types = "${var.cluster_enabled_log_types}" - role_arn = "${aws_iam_role.cluster.arn}" + role_arn = "${local.cluster_iam_role_arn}" version = "${var.cluster_version}" vpc_config { @@ -58,14 +58,17 @@ resource "aws_iam_role" "cluster" { permissions_boundary = "${var.permissions_boundary}" path = "${var.iam_path}" force_detach_policies = true + count = "${var.manage_cluster_iam_resources ? 1 : 0}" } resource "aws_iam_role_policy_attachment" "cluster_AmazonEKSClusterPolicy" { policy_arn = "arn:aws:iam::aws:policy/AmazonEKSClusterPolicy" role = "${aws_iam_role.cluster.name}" + count = "${var.manage_cluster_iam_resources ? 1 : 0}" } resource "aws_iam_role_policy_attachment" "cluster_AmazonEKSServicePolicy" { policy_arn = "arn:aws:iam::aws:policy/AmazonEKSServicePolicy" role = "${aws_iam_role.cluster.name}" + count = "${var.manage_cluster_iam_resources ? 1 : 0}" } diff --git a/data.tf b/data.tf index e0e664a..72d2a81 100644 --- a/data.tf +++ b/data.tf @@ -100,3 +100,18 @@ data "template_file" "launch_template_userdata" { kubelet_extra_args = "${lookup(var.worker_groups_launch_template[count.index], "kubelet_extra_args", local.workers_group_launch_template_defaults["kubelet_extra_args"])}" } } + +data "aws_iam_role" "custom_cluster_iam_role" { + name = "${var.cluster_iam_role_name}" + count = "${var.manage_cluster_iam_resources ? 0 : 1}" +} + +data "aws_iam_instance_profile" "custom_worker_group_iam_instance_profile" { + name = "${lookup(var.worker_groups[count.index], "iam_instance_profile_name", local.workers_group_defaults["iam_instance_profile_name"])}" + count = "${var.manage_worker_iam_resources ? 0 : var.worker_group_count}" +} + +data "aws_iam_instance_profile" "custom_worker_group_launch_template_iam_instance_profile" { + name = "${lookup(var.worker_groups_launch_template[count.index], "iam_instance_profile_name", local.workers_group_launch_template_defaults["iam_instance_profile_name"])}" + count = "${var.manage_worker_iam_resources ? 0 : var.worker_group_launch_template_count}" +} diff --git a/local.tf b/local.tf index 3f6149d..e87c1fe 100644 --- a/local.tf +++ b/local.tf @@ -5,6 +5,9 @@ locals { # to workaround terraform not supporting short circut evaluation cluster_security_group_id = "${coalesce(join("", aws_security_group.cluster.*.id), var.cluster_security_group_id)}" + cluster_iam_role_name = "${coalesce(join("", aws_iam_role.cluster.*.name), var.cluster_iam_role_name)}" + cluster_iam_role_arn = "${coalesce(join("", aws_iam_role.cluster.*.arn), join("", data.aws_iam_role.custom_cluster_iam_role.*.arn))}" + worker_security_group_id = "${coalesce(join("", aws_security_group.workers.*.id), var.worker_security_group_id)}" default_iam_role_id = "${element(concat(aws_iam_role.workers.*.id, list("")), 0)}" kubeconfig_name = "${var.kubeconfig_name == "" ? "eks_${var.cluster_name}" : var.kubeconfig_name}" @@ -34,7 +37,8 @@ locals { autoscaling_enabled = false # Sets whether policy and matching tags will be added to allow autoscaling. additional_security_group_ids = "" # A comma delimited list of additional security group ids to include in worker launch config protect_from_scale_in = false # Prevent AWS from scaling in, so that cluster-autoscaler is solely responsible. - iam_role_id = "${local.default_iam_role_id}" # Use the specified IAM role if set. + iam_instance_profile_name = "" # A custom IAM instance profile name. Used when manage_worker_iam_resources is set to false. Incompatible with iam_role_id. + iam_role_id = "${local.default_iam_role_id}" # A custom IAM role id. Incompatible with iam_instance_profile_name. suspended_processes = "AZRebalance" # A comma delimited string of processes to to suspend. i.e. AZRebalance,HealthCheck,ReplaceUnhealthy target_group_arns = "" # A comma delimited list of ALB target group ARNs to be associated to the ASG enabled_metrics = "" # A comma delimited list of metrics to be collected i.e. GroupMinSize,GroupMaxSize,GroupDesiredCapacity @@ -79,7 +83,8 @@ locals { autoscaling_enabled = false # Sets whether policy and matching tags will be added to allow autoscaling. additional_security_group_ids = "" # A comma delimited list of additional security group ids to include in worker launch config protect_from_scale_in = false # Prevent AWS from scaling in, so that cluster-autoscaler is solely responsible. - iam_role_id = "${local.default_iam_role_id}" # Use the specified IAM role if set. + iam_instance_profile_name = "" # A custom IAM instance profile name. Used when manage_worker_iam_resources is set to false. Incompatible with iam_role_id. + iam_role_id = "${local.default_iam_role_id}" # A custom IAM role id. Incompatible with iam_instance_profile_name. suspended_processes = "AZRebalance" # A comma delimited string of processes to to suspend. i.e. AZRebalance,HealthCheck,ReplaceUnhealthy target_group_arns = "" # A comma delimited list of ALB target group ARNs to be associated to the ASG enabled_metrics = "" # A comma delimited list of metrics to be collected i.e. GroupMinSize,GroupMaxSize,GroupDesiredCapacity diff --git a/outputs.tf b/outputs.tf index 2bca309..c99c58d 100644 --- a/outputs.tf +++ b/outputs.tf @@ -35,12 +35,12 @@ output "config_map_aws_auth" { output "cluster_iam_role_name" { description = "IAM role name of the EKS cluster." - value = "${aws_iam_role.cluster.name}" + value = "${local.cluster_iam_role_name}" } output "cluster_iam_role_arn" { description = "IAM role ARN of the EKS cluster." - value = "${aws_iam_role.cluster.arn}" + value = "${local.cluster_iam_role_arn}" } output "kubeconfig" { @@ -105,10 +105,10 @@ output "worker_iam_instance_profile_names" { output "worker_iam_role_name" { description = "default IAM role name for EKS worker groups" - value = "${aws_iam_role.workers.name}" + value = "${element(coalescelist(aws_iam_role.workers.*.name, data.aws_iam_instance_profile.custom_worker_group_iam_instance_profile.*.role_name, data.aws_iam_instance_profile.custom_worker_group_launch_template_iam_instance_profile.*.role_name), 0)}" } output "worker_iam_role_arn" { description = "default IAM role ARN for EKS worker groups" - value = "${aws_iam_role.workers.arn}" + value = "${element(coalescelist(aws_iam_role.workers.*.arn, data.aws_iam_instance_profile.custom_worker_group_iam_instance_profile.*.role_arn, data.aws_iam_instance_profile.custom_worker_group_launch_template_iam_instance_profile.*.role_arn), 0)}" } diff --git a/variables.tf b/variables.tf index 9c35afe..94c1323 100644 --- a/variables.tf +++ b/variables.tf @@ -257,3 +257,18 @@ variable "cluster_endpoint_public_access" { description = "Indicates whether or not the Amazon EKS public API server endpoint is enabled." default = true } + +variable "manage_cluster_iam_resources" { + description = "Whether to let the module manage cluster IAM resources. If set to false, cluster_iam_role_name must be specified." + default = true +} + +variable "cluster_iam_role_name" { + description = "IAM role name for the cluster. Only applicable if manage_cluster_iam_resources is set to false." + default = "" +} + +variable "manage_worker_iam_resources" { + description = "Whether to let the module manage worker IAM resources. If set to false, iam_instance_profile_name must be specified for workers." + default = true +} diff --git a/workers.tf b/workers.tf index 7790c62..5a68615 100644 --- a/workers.tf +++ b/workers.tf @@ -38,7 +38,7 @@ resource "aws_launch_configuration" "workers" { name_prefix = "${aws_eks_cluster.this.name}-${lookup(var.worker_groups[count.index], "name", count.index)}" associate_public_ip_address = "${lookup(var.worker_groups[count.index], "public_ip", local.workers_group_defaults["public_ip"])}" security_groups = ["${local.worker_security_group_id}", "${var.worker_additional_security_group_ids}", "${compact(split(",",lookup(var.worker_groups[count.index],"additional_security_group_ids", local.workers_group_defaults["additional_security_group_ids"])))}"] - iam_instance_profile = "${element(aws_iam_instance_profile.workers.*.id, count.index)}" + iam_instance_profile = "${element(coalescelist(aws_iam_instance_profile.workers.*.id, data.aws_iam_instance_profile.custom_worker_group_iam_instance_profile.*.name), count.index)}" image_id = "${lookup(var.worker_groups[count.index], "ami_id", local.workers_group_defaults["ami_id"])}" instance_type = "${lookup(var.worker_groups[count.index], "instance_type", local.workers_group_defaults["instance_type"])}" key_name = "${lookup(var.worker_groups[count.index], "key_name", local.workers_group_defaults["key_name"])}" @@ -131,32 +131,36 @@ resource "aws_iam_role" "workers" { permissions_boundary = "${var.permissions_boundary}" path = "${var.iam_path}" force_detach_policies = true + count = "${var.manage_worker_iam_resources ? 1 : 0}" } resource "aws_iam_instance_profile" "workers" { name_prefix = "${aws_eks_cluster.this.name}" role = "${lookup(var.worker_groups[count.index], "iam_role_id", lookup(local.workers_group_defaults, "iam_role_id"))}" - count = "${var.worker_group_count}" + count = "${var.manage_worker_iam_resources ? var.worker_group_count : 0}" path = "${var.iam_path}" } resource "aws_iam_role_policy_attachment" "workers_AmazonEKSWorkerNodePolicy" { policy_arn = "arn:aws:iam::aws:policy/AmazonEKSWorkerNodePolicy" role = "${aws_iam_role.workers.name}" + count = "${var.manage_worker_iam_resources ? 1 : 0}" } resource "aws_iam_role_policy_attachment" "workers_AmazonEKS_CNI_Policy" { policy_arn = "arn:aws:iam::aws:policy/AmazonEKS_CNI_Policy" role = "${aws_iam_role.workers.name}" + count = "${var.manage_worker_iam_resources ? 1 : 0}" } resource "aws_iam_role_policy_attachment" "workers_AmazonEC2ContainerRegistryReadOnly" { policy_arn = "arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly" role = "${aws_iam_role.workers.name}" + count = "${var.manage_worker_iam_resources ? 1 : 0}" } resource "aws_iam_role_policy_attachment" "workers_additional_policies" { - count = "${var.workers_additional_policies_count}" + count = "${var.manage_worker_iam_resources ? var.workers_additional_policies_count : 0}" role = "${aws_iam_role.workers.name}" policy_arn = "${var.workers_additional_policies[count.index]}" } @@ -174,6 +178,7 @@ resource "null_resource" "tags_as_list_of_maps" { resource "aws_iam_role_policy_attachment" "workers_autoscaling" { policy_arn = "${aws_iam_policy.worker_autoscaling.arn}" role = "${aws_iam_role.workers.name}" + count = "${var.manage_worker_iam_resources ? 1 : 0}" } resource "aws_iam_policy" "worker_autoscaling" { @@ -181,6 +186,7 @@ resource "aws_iam_policy" "worker_autoscaling" { description = "EKS worker node autoscaling policy for cluster ${aws_eks_cluster.this.name}" policy = "${data.aws_iam_policy_document.worker_autoscaling.json}" path = "${var.iam_path}" + count = "${var.manage_worker_iam_resources ? 1 : 0}" } data "aws_iam_policy_document" "worker_autoscaling" { diff --git a/workers_launch_template.tf b/workers_launch_template.tf index c28ca74..73b31bc 100644 --- a/workers_launch_template.tf +++ b/workers_launch_template.tf @@ -75,7 +75,7 @@ resource "aws_launch_template" "workers_launch_template" { } iam_instance_profile { - name = "${element(aws_iam_instance_profile.workers_launch_template.*.name, count.index)}" + name = "${element(coalescelist(aws_iam_instance_profile.workers_launch_template.*.name, data.aws_iam_instance_profile.custom_worker_group_launch_template_iam_instance_profile.*.name), count.index)}" } image_id = "${lookup(var.worker_groups_launch_template[count.index], "ami_id", local.workers_group_launch_template_defaults["ami_id"])}" @@ -118,6 +118,6 @@ resource "aws_launch_template" "workers_launch_template" { resource "aws_iam_instance_profile" "workers_launch_template" { name_prefix = "${aws_eks_cluster.this.name}" role = "${lookup(var.worker_groups_launch_template[count.index], "iam_role_id", lookup(local.workers_group_launch_template_defaults, "iam_role_id"))}" - count = "${var.worker_group_launch_template_count}" + count = "${var.manage_worker_iam_resources ? var.worker_group_launch_template_count : 0}" path = "${var.iam_path}" }