diff --git a/README.md b/README.md index b09d2da..4cdfd33 100644 --- a/README.md +++ b/README.md @@ -119,6 +119,10 @@ The project is split into four main Terraform configurations: Monitoring infrastructure. **This applies to both dev and prod environments**. You can switch between workspaces (as mentioned earlier) to deploy infrastructure in either the dev or prod account. +- [21-continuous-delivery][cd]: This configuration contains the definition of the IAM roles that + allow access to GitHub Action for specific repositories and operations. **This applies to both + dev and prod environments**. You can switch between workspaces (as mentioned earlier) to deploy + infrastructure in either the dev or prod account. ### System Flow Overview @@ -170,3 +174,4 @@ This project is licensed under the [MIT License](LICENSE). [route-53]: /pillarbox-monitoring-terraform/10-pillarbox-monitoring-route-53 [ecr]: /pillarbox-monitoring-terraform/11-pillarbox-monitoring-ecr [app]: /pillarbox-monitoring-terraform/20-pillarbox-monitoring-app +[cd]: /pillarbox-monitoring-terraform/21-continuous-delivery diff --git a/pillarbox-monitoring-terraform/11-pillarbox-monitoring-ecr/main.tf b/pillarbox-monitoring-terraform/11-pillarbox-monitoring-ecr/main.tf index 3211d4d..55ff3cf 100644 --- a/pillarbox-monitoring-terraform/11-pillarbox-monitoring-ecr/main.tf +++ b/pillarbox-monitoring-terraform/11-pillarbox-monitoring-ecr/main.tf @@ -77,94 +77,6 @@ resource "aws_ecr_lifecycle_policy" "ecr_lifecycles" { EOF } -# ----------------------------------- -# IAM Configuration for GitHub Actions -# ----------------------------------- - -## Set Up OIDC Provider - -resource "aws_iam_openid_connect_provider" "github_actions" { - # Create an IAM OIDC provider for GitHub Actions - url = "https://token.actions.githubusercontent.com" - client_id_list = ["sts.amazonaws.com"] - thumbprint_list = var.github_thumbprint_list -} - -## Define IAM Policy Documents - -### Assume Role Policy Document - -data "aws_iam_policy_document" "gha_assume_policy" { - # Generate policy documents for assuming IAM roles via OIDC - for_each = var.ecr_repositories - - statement { - effect = "Allow" - actions = ["sts:AssumeRoleWithWebIdentity"] - principals { - type = "Federated" - identifiers = [aws_iam_openid_connect_provider.github_actions.arn] - } - condition { - test = "StringEquals" - variable = "token.actions.githubusercontent.com:aud" - values = ["sts.amazonaws.com"] - } - condition { - test = "StringLike" - variable = "token.actions.githubusercontent.com:sub" - values = ["repo:${each.value}:*"] - } - } -} - -### Permissions Policy Document - -data "aws_iam_policy_document" "gha_policy" { - # Define permissions for GitHub Actions to interact with ECR - for_each = var.ecr_repositories - - # Allow Docker login to ECR - statement { - sid = "AllowDockerLogin" - effect = "Allow" - actions = ["ecr:GetAuthorizationToken"] - resources = ["*"] - } - - # Allow pushing and pulling images to/from ECR - statement { - sid = "AllowPushPull" - effect = "Allow" - actions = [ - "ecr:BatchGetImage", - "ecr:GetDownloadUrlForLayer", - "ecr:InitiateLayerUpload", - "ecr:UploadLayerPart", - "ecr:CompleteLayerUpload", - "ecr:BatchCheckLayerAvailability", - "ecr:PutImage" - ] - resources = [aws_ecr_repository.repositories[each.key].arn] - } -} - -## Create IAM Roles for GitHub Actions - -resource "aws_iam_role" "gha_role" { - # Create IAM roles for each ECR repository for GitHub Actions - for_each = var.ecr_repositories - - name = "gh-actions-role-${each.key}" - assume_role_policy = data.aws_iam_policy_document.gha_assume_policy[each.key].json - - # Attach inline policy for ECR permissions - inline_policy { - name = "GithubActionECRBuilds" - policy = data.aws_iam_policy_document.gha_policy[each.key].json - } -} - # ----------------------------------- # Cross-Account ECR Access Configuration # ----------------------------------- diff --git a/pillarbox-monitoring-terraform/11-pillarbox-monitoring-ecr/variables.tf b/pillarbox-monitoring-terraform/11-pillarbox-monitoring-ecr/variables.tf index 2b7c179..f1d4e44 100644 --- a/pillarbox-monitoring-terraform/11-pillarbox-monitoring-ecr/variables.tf +++ b/pillarbox-monitoring-terraform/11-pillarbox-monitoring-ecr/variables.tf @@ -1,13 +1,3 @@ -# See https://github.blog/changelog/2023-06-27-github-actions-update-on-oidc-integration-with-aws/ -variable "github_thumbprint_list" { - type = list(string) - description = "Github Thumbprint list" - default = [ - "6938fd4d98bab03faadb97b34396831e3780aea1", - "1c58a3a8518e8759bf075b76b750d4f2df264fcd" - ] -} - variable "ecr_repositories" { description = "Map of ECR repository names to their associated GitHub repository" type = map(string) diff --git a/pillarbox-monitoring-terraform/21-continuous-delivery/.terraform.lock.hcl b/pillarbox-monitoring-terraform/21-continuous-delivery/.terraform.lock.hcl new file mode 100644 index 0000000..6a1d7aa --- /dev/null +++ b/pillarbox-monitoring-terraform/21-continuous-delivery/.terraform.lock.hcl @@ -0,0 +1,25 @@ +# This file is maintained automatically by "terraform init". +# Manual edits may be lost in future updates. + +provider "registry.terraform.io/hashicorp/aws" { + version = "5.4.0" + constraints = "~> 5.4.0" + hashes = [ + "h1:V2yz+EYWnLU/fWdsk8UX7oFuAKTBLTHDdLKB6NG7th0=", + "zh:1db5f81089216831bb0fdff9ddc3772efa133397c66ec276bc75b96eec06e23f", + "zh:26fe5fdf399192b5724d21854fbec650c158f8ee9eb1dc52a50f7da0f2bc07ac", + "zh:2946d9e333b1efe01588ee9f9771169fd3c3a4a7cb78ed8f91e8b3efd1a73850", + "zh:36ed69e8d3029332c8a52a70940f714fd579b9fd95f5569cc010ef11162f5bf7", + "zh:46ba5ad1c3a3ef98c346356cfa4bdd9c2501c661c2513bb92f4413f2482fb24b", + "zh:46c10aaa9672b54a14b0e0effdd6ecd9b8a539b3bfe273ac54111e7352a7bb4b", + "zh:47d7f57bcbe4fba2f960ab6c4228c5e9e586be2f233a8baa8962b51a63337179", + "zh:47e41c198439ba1c4d933f808b6f47e518f8f0aae25ca42abcac97f149121e90", + "zh:526c5834de71654ee14039cb973322bf5032cb684a2a113b48fb48a0584f46f3", + "zh:6169316517b95677819ba2904dcea204fb9b55e868348e906af9164104fe7198", + "zh:7c063ef2b8d69a8db7e8bf0dcd45793ede22b259b30464ed114d330df304cdbb", + "zh:87c4f2faca636715a08be3121d26b3354415401eab89349077ca9436a0822c23", + "zh:9b12af85486a96aedd8d7984b0ff811a4b42e3d88dad1a3fb4c0b580d04fa425", + "zh:b184b8a268f45258edd27d389ca793708f1bc3ee4d6706d154a45e93deaddde1", + "zh:ba1a998cbf4b639fa3e04b9069f0f5a289662457940726a8a51c81df400aa852", + ] +} diff --git a/pillarbox-monitoring-terraform/21-continuous-delivery/locals.tf b/pillarbox-monitoring-terraform/21-continuous-delivery/locals.tf new file mode 100644 index 0000000..880e81e --- /dev/null +++ b/pillarbox-monitoring-terraform/21-continuous-delivery/locals.tf @@ -0,0 +1,12 @@ +locals { + ecs_cluster_name = "${var.application_name}-cluster" + is_prod = terraform.workspace == "prod" + + default_tags = { + "srg-managed-by" = "terraform" + "srg-application" = var.application_name + "srg-owner" = "pillarbox-team@rts.ch" + "srg-businessowner" = "pillarbox" + "srg-environment" = terraform.workspace + } +} diff --git a/pillarbox-monitoring-terraform/21-continuous-delivery/main.tf b/pillarbox-monitoring-terraform/21-continuous-delivery/main.tf new file mode 100644 index 0000000..eeeda5d --- /dev/null +++ b/pillarbox-monitoring-terraform/21-continuous-delivery/main.tf @@ -0,0 +1,158 @@ +# ----------------------------------- +# Terraform Configuration +# ----------------------------------- + +terraform { + # Backend configuration for storing the Terraform state in S3 with DynamoDB table for state locking + backend "s3" { + encrypt = true + bucket = "pillarbox-monitoring-tfstate" + key = "terraform/21-continuous-delivery/terraform.tfstate" + dynamodb_table = "pillarbox-monitoring-terraform-statelock" + profile = "prod" + } + + # Specify required providers and their versions + required_providers { + aws = { + source = "hashicorp/aws" + version = "~>5.4.0" + } + } +} + +# ----------------------------------- +# AWS Provider Setup +# ----------------------------------- + +provider "aws" { + # Apply default tags to all AWS resources + default_tags { + tags = local.default_tags + } +} + +# ----------------------------------- +# AWS Data Sources +# ----------------------------------- + +# Get current AWS region +data "aws_region" "current" {} + +# Get current AWS identity +data "aws_caller_identity" "current" {} + +# ----------------------------------- +# IAM Configuration for GitHub Actions +# ----------------------------------- + +## Set Up OIDC Provider + +resource "aws_iam_openid_connect_provider" "github_actions" { + # Create an IAM OIDC provider for GitHub Actions + url = "https://token.actions.githubusercontent.com" + client_id_list = ["sts.amazonaws.com"] + thumbprint_list = var.github_thumbprint_list +} + +## Define IAM Policy Documents + +### Assume Role Policy Document + +data "aws_iam_policy_document" "gha_assume_policy" { + # Generate policy documents for assuming IAM roles via OIDC + for_each = var.service_mappings + + statement { + effect = "Allow" + actions = ["sts:AssumeRoleWithWebIdentity"] + principals { + type = "Federated" + identifiers = [aws_iam_openid_connect_provider.github_actions.arn] + } + condition { + test = "StringEquals" + variable = "token.actions.githubusercontent.com:aud" + values = ["sts.amazonaws.com"] + } + condition { + test = "StringLike" + variable = "token.actions.githubusercontent.com:sub" + values = ["repo:${each.value.github_repo_name}:*"] + } + } +} + +### Permissions Policy Document + +data "aws_iam_policy_document" "gha_policy" { + # Define permissions for GitHub Actions to interact with ECR and ECS + for_each = var.service_mappings + + # Allow Docker login to ECR + dynamic "statement" { + for_each = local.is_prod ? [1] : [] + + content { + sid = "AllowDockerLogin" + effect = "Allow" + actions = ["ecr:GetAuthorizationToken"] + resources = ["*"] + } + } + + # Allow pushing and pulling images to/from ECR + dynamic "statement" { + for_each = local.is_prod ? [1] : [] + + content { + sid = "AllowPushPull" + effect = "Allow" + actions = [ + "ecr:BatchGetImage", + "ecr:GetDownloadUrlForLayer", + "ecr:InitiateLayerUpload", + "ecr:UploadLayerPart", + "ecr:CompleteLayerUpload", + "ecr:BatchCheckLayerAvailability", + "ecr:PutImage" + ] + resources = [ + "arn:aws:ecr:${data.aws_region.current.name}:${data.aws_caller_identity.current.account_id}:repository/${each.value.ecr_image_name}" + ] + + } + } + + # Allow updating ECS services + statement { + sid = "AllowUpdateService" + effect = "Allow" + actions = [ + "ecs:UpdateService", + "ecs:DescribeServices" + ] + resources = [ + "arn:aws:ecs:${data.aws_region.current.name}:${data.aws_caller_identity.current.account_id}:cluster/${local.ecs_cluster_name}", + "arn:aws:ecs:${data.aws_region.current.name}:${data.aws_caller_identity.current.account_id}:service/${local.ecs_cluster_name}/${each.key}" + ] + } +} + +## Create IAM Roles for GitHub Actions + +resource "aws_iam_role" "gha_role" { + # Create IAM roles for each service + for_each = var.service_mappings + + name = "gh-actions-role-${each.key}" + assume_role_policy = data.aws_iam_policy_document.gha_assume_policy[each.key].json + + # Attach inline policy for ECR and ECS permissions + inline_policy { + name = "GithubActionPermissions" + policy = data.aws_iam_policy_document.gha_policy[each.key].json + } +} + + diff --git a/pillarbox-monitoring-terraform/21-continuous-delivery/variables.tf b/pillarbox-monitoring-terraform/21-continuous-delivery/variables.tf new file mode 100644 index 0000000..bd50317 --- /dev/null +++ b/pillarbox-monitoring-terraform/21-continuous-delivery/variables.tf @@ -0,0 +1,34 @@ +variable "application_name" { + description = "The name of the application" + type = string + default = "pillarbox-monitoring" +} + +# See https://github.blog/changelog/2023-06-27-github-actions-update-on-oidc-integration-with-aws/ +variable "github_thumbprint_list" { + type = list(string) + description = "Github Thumbprint list" + default = [ + "6938fd4d98bab03faadb97b34396831e3780aea1", + "1c58a3a8518e8759bf075b76b750d4f2df264fcd" + ] +} + +variable "service_mappings" { + description = "Service mapping to Github repository and ECR image name" + type = map(object({ + github_repo_name = string + ecr_image_name = string + })) + + default = { + "dispatch-service" = { + github_repo_name = "SRGSSR/pillarbox-event-dispatcher" + ecr_image_name = "pillarbox-event-dispatcher" + } + "data-transfer-service" = { + github_repo_name = "SRGSSR/pillarbox-monitoring-transfer" + ecr_image_name = "pillarbox-monitoring-transfer" + } + } +}