Skip to content

Commit

Permalink
Merge pull request #76 from ministryofjustice/oidc-refactor
Browse files Browse the repository at this point in the history
Refactor GitHub OIDC integration
  • Loading branch information
jakemulley authored May 9, 2023
2 parents e604a82 + c9142a2 commit 5db7b4f
Show file tree
Hide file tree
Showing 2 changed files with 85 additions and 88 deletions.
10 changes: 5 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,29 +40,29 @@ No modules.
| [aws_ecr_repository.repo](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ecr_repository) | resource |
| [aws_iam_access_key.key_2023](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_access_key) | resource |
| [aws_iam_policy.ecr](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource |
| [aws_iam_role.oidc](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource |
| [aws_iam_role_policy_attachment.ecr](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource |
| [aws_iam_role.github](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource |
| [aws_iam_role_policy_attachment.github_ecr](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource |
| [aws_iam_user.user](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_user) | resource |
| [aws_iam_user_policy.policy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_user_policy) | resource |
| [github_actions_environment_secret.ecr_access_key](https://registry.terraform.io/providers/integrations/github/latest/docs/resources/actions_environment_secret) | resource |
| [github_actions_environment_secret.ecr_name](https://registry.terraform.io/providers/integrations/github/latest/docs/resources/actions_environment_secret) | resource |
| [github_actions_environment_secret.ecr_role_to_assume](https://registry.terraform.io/providers/integrations/github/latest/docs/resources/actions_environment_secret) | resource |
| [github_actions_environment_secret.ecr_secret_key](https://registry.terraform.io/providers/integrations/github/latest/docs/resources/actions_environment_secret) | resource |
| [github_actions_environment_secret.ecr_url](https://registry.terraform.io/providers/integrations/github/latest/docs/resources/actions_environment_secret) | resource |
| [github_actions_environment_secret.role_to_assume](https://registry.terraform.io/providers/integrations/github/latest/docs/resources/actions_environment_secret) | resource |
| [github_actions_environment_variable.ecr_region](https://registry.terraform.io/providers/integrations/github/latest/docs/resources/actions_environment_variable) | resource |
| [github_actions_environment_variable.ecr_repository](https://registry.terraform.io/providers/integrations/github/latest/docs/resources/actions_environment_variable) | resource |
| [github_actions_secret.ecr_access_key](https://registry.terraform.io/providers/integrations/github/latest/docs/resources/actions_secret) | resource |
| [github_actions_secret.ecr_name](https://registry.terraform.io/providers/integrations/github/latest/docs/resources/actions_secret) | resource |
| [github_actions_secret.ecr_role_to_assume](https://registry.terraform.io/providers/integrations/github/latest/docs/resources/actions_secret) | resource |
| [github_actions_secret.ecr_secret_key](https://registry.terraform.io/providers/integrations/github/latest/docs/resources/actions_secret) | resource |
| [github_actions_secret.ecr_url](https://registry.terraform.io/providers/integrations/github/latest/docs/resources/actions_secret) | resource |
| [github_actions_secret.role_to_assume](https://registry.terraform.io/providers/integrations/github/latest/docs/resources/actions_secret) | resource |
| [github_actions_variable.ecr_region](https://registry.terraform.io/providers/integrations/github/latest/docs/resources/actions_variable) | resource |
| [github_actions_variable.ecr_repository](https://registry.terraform.io/providers/integrations/github/latest/docs/resources/actions_variable) | resource |
| [random_id.oidc](https://registry.terraform.io/providers/hashicorp/random/latest/docs/resources/id) | resource |
| [random_id.user](https://registry.terraform.io/providers/hashicorp/random/latest/docs/resources/id) | resource |
| [aws_caller_identity.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/caller_identity) | data source |
| [aws_iam_openid_connect_provider.github](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_openid_connect_provider) | data source |
| [aws_iam_policy_document.ecr](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source |
| [aws_iam_policy_document.base](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source |
| [aws_iam_policy_document.github](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source |
| [aws_iam_policy_document.policy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source |
| [aws_region.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/region) | data source |
Expand Down
163 changes: 80 additions & 83 deletions main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -167,59 +167,43 @@ resource "github_actions_environment_secret" "ecr_secret_key" {
# OIDC integration #
####################
locals {
# Identifiers
oidc_identifier = "cloud-platform-ecr-${random_id.oidc.hex}"

# Providers
oidc_providers = {
github = "token.actions.githubusercontent.com"
}

oidc_providers_assume_role_policies = {
github = data.aws_iam_policy_document.github.json
# GitHub
enable_github = contains(var.oidc_providers, "github")
github_repos = toset(var.github_repositories)
github_envs = toset(var.github_environments)
github_repo_envs = {
for pair in setproduct(local.github_repos, local.github_envs) :
"${pair[0]}.${pair[1]}" => {
repository = pair[0]
environment = pair[1]
}
}
github_actions_prefix = upper(var.github_actions_prefix)
github_variable_names = {
ECR_ROLE_TO_ASSUME = join("_", compact([local.github_actions_prefix, "ECR_ROLE_TO_ASSUME"]))
ECR_REGION = join("_", compact([local.github_actions_prefix, "ECR_REGION"]))
ECR_REPOSITORY = join("_", compact([local.github_actions_prefix, "ECR_REPOSITORY"]))
}

identifier_oidc = "cloud-platform-ecr-${random_id.oidc.hex}"
}

# Random ID for identifiers
resource "random_id" "oidc" {
byte_length = 8
}

# GitHub: OIDC provider
data "aws_iam_openid_connect_provider" "github" {
url = "https://${local.oidc_providers.github}"
}

# GitHub: Assume role policy
# See: https://docs.github.com/en/actions/deployment/security-hardening-your-deployments/configuring-openid-connect-in-amazon-web-services#adding-the-identity-provider-to-aws
data "aws_iam_policy_document" "github" {
version = "2012-10-17"

statement {
effect = "Allow"
actions = ["sts:AssumeRoleWithWebIdentity"]

principals {
type = "Federated"
identifiers = [data.aws_iam_openid_connect_provider.github.arn]
}

condition {
test = length(var.github_repositories) == 1 ? "StringLike" : "ForAnyValue:StringLike"
variable = "${local.oidc_providers.github}:sub"
values = formatlist("repo:ministryofjustice/%s:*", toset(var.github_repositories))
}

condition {
test = "StringEquals"
variable = "${local.oidc_providers.github}:aud"
values = ["sts.amazonaws.com"]
}
}
}

# ECR policy
# Base ECR policy for pushing and pulling images, can be used across all OIDC providers
# See: https://github.com/aws-actions/amazon-ecr-login#permissions
data "aws_iam_policy_document" "ecr" {
data "aws_iam_policy_document" "base" {
version = "2012-10-17"

statement {
sid = "AllowLogin"
effect = "Allow"
Expand All @@ -243,86 +227,99 @@ data "aws_iam_policy_document" "ecr" {
}
}

# IAM roles, policies, and policy attachments
resource "aws_iam_role" "oidc" {
for_each = toset(var.oidc_providers) # one role per provider
# You can reuse this policy across multiple roles
resource "aws_iam_policy" "ecr" {
count = (length(var.oidc_providers) > 0) ? 1 : 0

name = "${local.identifier_oidc}-${each.key}"
assume_role_policy = local.oidc_providers_assume_role_policies[each.key]
name = local.oidc_identifier
policy = data.aws_iam_policy_document.base.json
}

resource "aws_iam_policy" "ecr" {
name = local.identifier_oidc
policy = data.aws_iam_policy_document.ecr.json
# GitHub: OIDC provider
data "aws_iam_openid_connect_provider" "github" {
url = "https://${local.oidc_providers.github}"
}

resource "aws_iam_role_policy_attachment" "ecr" {
for_each = aws_iam_role.oidc
# GitHub: Assume role policy
# See: https://docs.github.com/en/actions/deployment/security-hardening-your-deployments/configuring-openid-connect-in-amazon-web-services#adding-the-identity-provider-to-aws
data "aws_iam_policy_document" "github" {
version = "2012-10-17"

role = each.value.name
policy_arn = aws_iam_policy.ecr.arn
}
statement {
effect = "Allow"
actions = ["sts:AssumeRoleWithWebIdentity"]

# GitHub Actions variables and secrets
locals {
github_variable_names = {
ECR_ROLE_TO_ASSUME = upper(join("_", compact([var.github_actions_prefix, "ECR_ROLE_TO_ASSUME"])))
ECR_REGION = upper(join("_", compact([var.github_actions_prefix, "ECR_REGION"])))
ECR_REPOSITORY = upper(join("_", compact([var.github_actions_prefix, "ECR_REPOSITORY"])))
}
principals {
type = "Federated"
identifiers = [data.aws_iam_openid_connect_provider.github.arn]
}

github_repos = toset(var.github_repositories)
github_envs = toset(var.github_environments)
github_repo_envs = {
for pair in setproduct(local.github_repos, local.github_envs) :
"${pair[0]}.${pair[1]}" => {
repository = pair[0]
environment = pair[1]
condition {
test = (length(local.github_repos) == 1) ? "StringLike" : "ForAnyValue:StringLike"
variable = "${local.oidc_providers.github}:sub"
values = formatlist("repo:ministryofjustice/%s:*", local.github_repos)
}

condition {
test = "StringEquals"
variable = "${local.oidc_providers.github}:aud"
values = ["sts.amazonaws.com"]
}
}
}

# IAM role and policy attachment for ECR
resource "aws_iam_role" "github" {
count = local.enable_github ? 1 : 0

name = "${local.oidc_identifier}-github"
assume_role_policy = data.aws_iam_policy_document.github.json
}

resource "aws_iam_role_policy_attachment" "github_ecr" {
count = local.enable_github ? 1 : 0

role = aws_iam_role.github[0].name
policy_arn = aws_iam_policy.ecr[0].arn
}

# Actions
resource "github_actions_secret" "role_to_assume" {
for_each = contains(var.oidc_providers, "github") ? local.github_repos : []
resource "github_actions_secret" "ecr_role_to_assume" {
for_each = local.enable_github ? local.github_repos : []

repository = each.key
repository = each.value
secret_name = local.github_variable_names["ECR_ROLE_TO_ASSUME"]
plaintext_value = aws_iam_role.oidc["github"].arn

depends_on = [aws_iam_role.oidc]
plaintext_value = aws_iam_role.github[0].arn
}

resource "github_actions_variable" "ecr_region" {
for_each = local.github_repos
for_each = local.enable_github ? local.github_repos : []

repository = each.key
repository = each.value
variable_name = local.github_variable_names["ECR_REGION"]
value = data.aws_region.current.name
}

resource "github_actions_variable" "ecr_repository" {
for_each = local.github_repos
for_each = local.enable_github ? local.github_repos : []

repository = each.key
repository = each.value
variable_name = local.github_variable_names["ECR_REPOSITORY"]
value = aws_ecr_repository.repo.name
}

# Environments
resource "github_actions_environment_secret" "role_to_assume" {
for_each = contains(var.oidc_providers, "github") ? local.github_repo_envs : {}
resource "github_actions_environment_secret" "ecr_role_to_assume" {
for_each = local.enable_github ? local.github_repo_envs : {}

repository = each.value.repository
environment = each.value.environment
secret_name = local.github_variable_names["ECR_ROLE_TO_ASSUME"]
plaintext_value = aws_iam_role.oidc["github"].arn

depends_on = [aws_iam_role.oidc]
plaintext_value = aws_iam_role.github[0].arn
}

resource "github_actions_environment_variable" "ecr_region" {
for_each = local.github_repo_envs
for_each = local.enable_github ? local.github_repo_envs : {}

repository = each.value.repository
environment = each.value.environment
Expand All @@ -331,7 +328,7 @@ resource "github_actions_environment_variable" "ecr_region" {
}

resource "github_actions_environment_variable" "ecr_repository" {
for_each = local.github_repo_envs
for_each = local.enable_github ? local.github_repo_envs : {}

repository = each.value.repository
environment = each.value.environment
Expand Down

0 comments on commit 5db7b4f

Please sign in to comment.