Skip to content
Merged
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
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -344,7 +344,7 @@ Use [iam-read-only-policy module](https://github.com/terraform-aws-modules/terra
- [iam-assumable-role-with-saml](https://github.com/terraform-aws-modules/terraform-aws-iam/tree/master/examples/iam-assumable-role-with-saml) - Create individual IAM role which can be assumed by users with a SAML Identity Provider
- [iam-assumable-roles](https://github.com/terraform-aws-modules/terraform-aws-iam/tree/master/examples/iam-assumable-roles) - Create several IAM roles which can be assumed from specified ARNs (AWS accounts, IAM users, etc)
- [iam-assumable-roles-with-saml](https://github.com/terraform-aws-modules/terraform-aws-iam/tree/master/examples/iam-assumable-roles-with-saml) - Create several IAM roles which can be assumed by users with a SAML Identity Provider
- [iam-eks-role](https://github.com/terraform-aws-modules/terraform-aws-iam/tree/master/examples/iam-eks-role) - Create an IAM role which can be assumed by one or more EKS `ServiceAccount`
- [iam-eks-role](https://github.com/terraform-aws-modules/terraform-aws-iam/tree/master/examples/iam-eks-role) - Create an IAM role that can be assumed by one or more EKS `ServiceAccount`
- [iam-group-complete](https://github.com/terraform-aws-modules/terraform-aws-iam/tree/master/examples/iam-group-complete) - IAM group with users who are allowed to assume IAM roles in another AWS account and have access to specified IAM policies
- [iam-group-with-assumable-roles-policy](https://github.com/terraform-aws-modules/terraform-aws-iam/tree/master/examples/iam-group-with-assumable-roles-policy) - IAM group with users who are allowed to assume IAM roles in the same or in separate AWS account
- [iam-group-with-policies](https://github.com/terraform-aws-modules/terraform-aws-iam/tree/master/examples/iam-group-with-policies) - IAM group with users who are allowed specified IAM policies (eg, "manage their own IAM user")
Expand Down
10 changes: 1 addition & 9 deletions examples/iam-eks-role/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,7 @@ module "iam_eks_role" {
role_name = "my-app"

cluster_service_accounts = {
(random_pet.this.id) = ["default:my-app", "canary:my-app"]
}

provider_url_sa_pairs = {
"oidc.eks.us-east-1.amazonaws.com/id/5C54DDF35ER19312844C7333374CC09D" = ["default:my-app2"]
"oidc.eks.ap-southeast-1.amazonaws.com/id/5C54DDF35ER54476848E7333374FF09G" = [
"default:my-app2",
"canary:my-app2",
]
(random_pet.this.id) = ["default:my-app"]
}

tags = {
Expand Down
67 changes: 46 additions & 21 deletions modules/iam-eks-role/README.md
Original file line number Diff line number Diff line change
@@ -1,52 +1,78 @@
# iam-eks-role

Creates single IAM role which can be assumed by one or more EKS `ServiceAccount` and optionally also OpenID Connect Federated Users.
Creates an IAM role that can be assumed by one or more EKS `ServiceAccount` in one or more EKS clusters. Unlike [iam-assumable-role-with-oidc](https://github.com/terraform-aws-modules/terraform-aws-iam/blob/master/modules/iam-assumable-role-with-oidc/), this module:

- Does not require any knowledge of cluster OIDC information as `data` resources are used
- Supports assuming the role from multiple EKS clusters, for example used in DR or when a workload is spread across clusters
- Support multiple `ServiceAccount` in the same cluster, for example when a workload runs in multiple namespaces
- More suitable for non-cluster admins as implementation is simpler
- More suitable for when the IAM role and cluster resources are in separate Terraform configurations

This module is for use with AWS EKS. For details of how a `ServiceAccount` in EKS can assume an IAM role, see the [EKS documentation](https://docs.aws.amazon.com/eks/latest/userguide/iam-roles-for-service-accounts.html).

This module supports multiple `ServiceAccount` in multiple clusters and/or namespaces. This allows for a single IAM role to be used when an application may span multiple clusters (e.g. for DR) or multiple namespaces (e.g. for canary deployments). The variables `cluster_service_accounts` and `provider_url_sa_pairs` are used for this as follows:
Implementation notes:

- The EKS cluster needs to exist first, in the current AWS account and region
- The key in the `cluster_service_accounts` is the exact name of the EKS cluster

## Basic example

To create an IAM role named `my-app` that can be assumed in EKS cluster `cluster1` by a `ServiceAccount` called `my-serviceaccount` in the `default` namespace:

```hcl
module "iam_eks_role" {
source = "terraform-aws-modules/iam/aws//modules/iam-eks-role"

role_name = "my-app"

cluster_service_accounts = {
"<EKS cluster name>" = [
"<namespace>:<ServiceAccount name>",
"<namespace>:<another ServiceAccount name>"
]
"cluster1" = ["default:my-serviceaccount"]
}
}
```

provider_url_sa_pairs = {
"<OIDC provider without protocol prefix>" = [
"<namespace>:<ServiceAccount name>",
"<namespace>:<another ServiceAccount name>"
]
## Multi cluster example:

To create an IAM role named `my-app` that can be assumed from:

- EKS cluster `staging-main-1`, namespace `default`, `ServiceAccount` called `my-app-staging`
- EKS cluster `staging-backup-1`, namespace `default`, `ServiceAccount` called `my-app-staging`

```hcl
module "iam_eks_role" {
source = "terraform-aws-modules/iam/aws//modules/iam-eks-role"

role_name = "my-app"

cluster_service_accounts = {
"staging-main-1" = ["default:my-app-staging"]
"staging-backup-1" = ["default:my-app-staging"]
}
}
```

For example, to create an IAM role named `my-app` that can be assumed from the `ServiceAccount` named `my-app-staging` in the namespace `default` and `canary` in EKS cluster named `cluster-main-1`; and also the `ServiceAccount` name `my-app-staging` in the namespace `default` in EKS cluster named `cluster-backup-1`, the configuration would be:
## Multi `ServiceAccount` example

To create an IAM role named `cloudwatch-exporter` that can be assumed in EKS cluster `production-main-1` from:

- namespace `kube-system`, `ServiceAccount` called `cloudwatch-exporter`
- namespace `app1`, `ServiceAccount` called `cloudwatch-exporter`

```hcl
module "iam_eks_role" {
source = "terraform-aws-modules/iam/aws//modules/iam-eks-role"

role_name = "my-app"

cluster_service_accounts = {
"cluster-main-1" = [
"default:my-app-staging",
"canary:my-app-staging"
],
"cluster-backup-1" = [
"default:my-app-staging",
"production-main-1" = [
"kube-system:cloudwatch-exporter",
"app1:cloudwatch-exporter",
]
}
}
```

Note: the EKS clusters must in the current AWS region and account as they use the default AWS provider.

<!-- BEGINNING OF PRE-COMMIT-TERRAFORM DOCS HOOK -->
## Requirements

Expand Down Expand Up @@ -84,7 +110,6 @@ No modules.
| <a name="input_create_role"></a> [create\_role](#input\_create\_role) | Whether to create a role | `bool` | `true` | no |
| <a name="input_force_detach_policies"></a> [force\_detach\_policies](#input\_force\_detach\_policies) | Whether policies should be detached from this role when destroying | `bool` | `false` | no |
| <a name="input_max_session_duration"></a> [max\_session\_duration](#input\_max\_session\_duration) | Maximum CLI/API session duration in seconds between 3600 and 43200 | `number` | `43200` | no |
| <a name="input_provider_url_sa_pairs"></a> [provider\_url\_sa\_pairs](#input\_provider\_url\_sa\_pairs) | OIDC provider URL and k8s ServiceAccount pairs. If the assume role policy requires a mix of EKS clusters and other OIDC providers then this can be used | `map(list(string))` | `{}` | no |
| <a name="input_role_description"></a> [role\_description](#input\_role\_description) | IAM Role description | `string` | `""` | no |
| <a name="input_role_name"></a> [role\_name](#input\_role\_name) | Name of IAM role | `string` | `null` | no |
| <a name="input_role_name_prefix"></a> [role\_name\_prefix](#input\_role\_name\_prefix) | IAM role name prefix | `string` | `null` | no |
Expand Down
24 changes: 0 additions & 24 deletions modules/iam-eks-role/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -32,30 +32,6 @@ data "aws_iam_policy_document" "assume_role_with_oidc" {
}
}
}

dynamic "statement" {
for_each = var.provider_url_sa_pairs

content {
effect = "Allow"

actions = ["sts:AssumeRoleWithWebIdentity"]

principals {
type = "Federated"

identifiers = [
"arn:aws:iam::${data.aws_caller_identity.current.account_id}:oidc-provider/${statement.key}"
]
}

condition {
test = "StringEquals"
variable = "${statement.key}:sub"
values = [for s in statement.value : "system:serviceaccount:${s}"]
}
}
}
}

resource "aws_iam_role" "this" {
Expand Down
8 changes: 4 additions & 4 deletions modules/iam-eks-role/outputs.tf
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
output "iam_role_arn" {
description = "ARN of IAM role"
value = element(concat(aws_iam_role.this.*.arn, [""]), 0)
value = try(aws_iam_role.this[0].arn, "")
}

output "iam_role_name" {
description = "Name of IAM role"
value = element(concat(aws_iam_role.this.*.name, [""]), 0)
value = try(aws_iam_role.this[0].name, "")
}

output "iam_role_path" {
description = "Path of IAM role"
value = element(concat(aws_iam_role.this.*.path, [""]), 0)
value = try(aws_iam_role.this[0].path, "")
}

output "iam_role_unique_id" {
description = "Unique ID of IAM role"
value = element(concat(aws_iam_role.this.*.unique_id, [""]), 0)
value = try(aws_iam_role.this[0].unique_id, "")
}
6 changes: 0 additions & 6 deletions modules/iam-eks-role/variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -46,12 +46,6 @@ variable "cluster_service_accounts" {
default = {}
}

variable "provider_url_sa_pairs" {
description = "OIDC provider URL and k8s ServiceAccount pairs. If the assume role policy requires a mix of EKS clusters and other OIDC providers then this can be used"
type = map(list(string))
default = {}
}

variable "tags" {
description = "A map of tags to add the the IAM role"
type = map(any)
Expand Down