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
1 change: 1 addition & 0 deletions modules/eks/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ Create a Kubernetes cluster using EKS.
| cluster\_version | EKS cluster version number to use. Incrementing this will start a cluster upgrade | `any` | n/a | yes |
| environment | The environment (development/staging/production) | `any` | n/a | yes |
| iam\_account\_id | Account ID of the current IAM user | `any` | n/a | yes |
| iam\_role\_mapping | List of mappings of users to roles | <pre>list(object({<br> name = string<br> arn = string<br> }))</pre> | n/a | yes |
| private\_subnets | VPC subnets for the EKS cluster | `any` | n/a | yes |
| project | Name of the project | `any` | n/a | yes |
| vpc\_id | VPC ID for EKS cluster | `any` | n/a | yes |
Expand Down
17 changes: 12 additions & 5 deletions modules/eks/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -45,13 +45,20 @@ module "eks" {
},
]

map_roles = [
{
map_roles = concat(
[{
rolearn = "arn:aws:iam::${var.iam_account_id}:role/${var.project}-kubernetes-admin-${var.environment}"
username = "${var.project}-kubernetes-admin"
username = "${var.project}-kubernetes-admin-${var.environment}"
groups = ["system:masters"]
},
]
}],
[
for r in var.iam_role_mapping : {
rolearn = r.arn
username = r.name
groups = [r.name]
}
]
)
cluster_iam_role_name = "k8s-${var.cluster_name}-cluster"
workers_role_name = "k8s-${var.cluster_name}-workers"

Expand Down
7 changes: 7 additions & 0 deletions modules/eks/variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -43,3 +43,10 @@ variable "iam_account_id" {
description = "Account ID of the current IAM user"
}

variable "iam_role_mapping" {
type = list(object({
name = string
arn = string
}))
description = "List of mappings of users to roles"
}
36 changes: 36 additions & 0 deletions modules/user_access/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# user_access

Create IAM Roles/Groups and Kubernetes Cluster Roles for user access

## Notes

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

| Name | Version |
|------|---------|
| terraform | >= 0.13 |

## Providers

| Name | Version |
|------|---------|
| aws | n/a |
| kubernetes | n/a |

## Inputs

| Name | Description | Type | Default | Required |
|------|-------------|------|---------|:--------:|
| environment | The environment (development/staging/production) | `any` | n/a | yes |
| project | Name of the project | `any` | n/a | yes |
| roles | Role list with policies | <pre>list(object({<br> name = string<br> aws_policy = string<br> k8s_policies = list(map(list(string)))<br> }))</pre> | n/a | yes |
| users | User list with roles | <pre>list(object({<br> name = string<br> roles = list(string)<br> }))</pre> | n/a | yes |

## Outputs

| Name | Description |
|------|-------------|
| eks\_iam\_role\_mapping | List of mappings of users to roles |

<!-- END OF PRE-COMMIT-TERRAFORM DOCS HOOK -->
100 changes: 100 additions & 0 deletions modules/user_access/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
# User and Roles

locals {
account_id = data.aws_caller_identity.current.account_id
}

# Create group with polcy for AWS resource access
resource "aws_iam_group" "access_group" {
count = length(var.roles)
name = "${var.project}-${var.roles[count.index].name}-${var.environment}"
path = "/users/"
}

data "aws_iam_policy_document" "access_group" {
count = length(var.roles)
source_json = var.roles[count.index].aws_policy

statement {
sid = "AssumeRolePolicy"
effect = "Allow"
actions = [
"iam:ListRoles",
"sts:AssumeRole"
]
resources = [aws_iam_role.access_assumerole[count.index].arn]
}
}

resource "aws_iam_policy" "access_group" {
count = length(var.roles)
name = aws_iam_group.access_group[count.index].name
description = "Group policy"
policy = data.aws_iam_policy_document.access_group[count.index].json
}

resource "aws_iam_group_policy_attachment" "access_group" {
count = length(var.roles)
group = aws_iam_group.access_group[count.index].name
policy_arn = aws_iam_policy.access_group[count.index].arn
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Instead of having the assumerole policy included in the policy that is passed in, we should be creating it here. (this code from zero-aws-eks-stack:)

  statement {
    effect = "Allow"
    actions = [
      "iam:ListRoles",
      "sts:AssumeRole"
    ]
    resources = ["arn:aws:iam::<% index .Params `accountId` %>:role/<% .Name %>-kubernetes-developer-prod"]
  }

It shouldn't be up to the user to have to include that policy block, we can create it dynamically here.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

done automatically in module side

resource "aws_iam_user_group_membership" "access_user_group" {
count = length(var.users)
user = "${var.project}-${var.users[count.index].name}"
groups = [for r in var.users[count.index].roles : "${var.project}-${r}-${var.environment}"]
}

# Create assumeroles with policy for Kubernetes aws-auth
resource "aws_iam_role" "access_assumerole" {
count = length(var.roles)
name = "${var.project}-kubernetes-${var.roles[count.index].name}-${var.environment}"
assume_role_policy = data.aws_iam_policy_document.access_assumerole_root_policy.json
description = "Assume role for Kubernetes aws-auth"
}

data "aws_caller_identity" "current" {}

data "aws_iam_policy_document" "access_assumerole_root_policy" {
statement {
actions = ["sts:AssumeRole"]

principals {
type = "AWS"
identifiers = [local.account_id]
}
}
}

# Create Kubernetes cluster role and group binding for API access
resource "kubernetes_cluster_role" "access_role" {
count = length(var.roles)
metadata {
name = aws_iam_role.access_assumerole[count.index].name
}

dynamic "rule" {
for_each = var.roles[count.index].k8s_policies
content {
verbs = rule.value.verbs
api_groups = rule.value.api_groups
resources = rule.value.resources
}
}
}

resource "kubernetes_cluster_role_binding" "access_role" {
count = length(var.roles)
metadata {
name = aws_iam_role.access_assumerole[count.index].name
}
subject {
kind = "Group"
name = kubernetes_cluster_role.access_role[count.index].metadata.0.name
}
role_ref {
api_group = "rbac.authorization.k8s.io"
kind = "ClusterRole"
name = kubernetes_cluster_role.access_role[count.index].metadata.0.name
}
}
10 changes: 10 additions & 0 deletions modules/user_access/outputs.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# output for EKS module
output "eks_iam_role_mapping" {
value = [
for r in aws_iam_role.access_assumerole : {
arn = r.arn
name = r.name
}
]
description = "List of mappings of users to roles"
}
24 changes: 24 additions & 0 deletions modules/user_access/variables.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
variable "project" {
description = "Name of the project"
}

variable "environment" {
description = "The environment (development/staging/production)"
}

variable "roles" {
type = list(object({
name = string
aws_policy = string
k8s_policies = list(map(list(string)))
}))
description = "Role list with policies"
}

variable "users" {
type = list(object({
name = string
roles = list(string)
}))
description = "User list with roles"
}
4 changes: 4 additions & 0 deletions modules/user_access/versions.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@

terraform {
required_version = ">= 0.13"
}