Skip to content

Commit

Permalink
Add aws-github-actions terraform module
Browse files Browse the repository at this point in the history
aws-github-actions terraform module helps create the IAM role and policy
with all the necessary permissions required for running the test
infrastructure, and also add the necessary secrets and variables to the
github repository. It expects GitHub OIDC to be registered as the
federated identity provider in the AWS account. More details can be
found in the README of the module.

Signed-off-by: Sunny <[email protected]>
  • Loading branch information
darkowlzz committed May 28, 2024
1 parent 2de4c29 commit 9455a99
Show file tree
Hide file tree
Showing 4 changed files with 291 additions and 0 deletions.
112 changes: 112 additions & 0 deletions tf-modules/aws/github-actions/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
# AWS GitHub Actions Secrets and Variables

This terraform module creates AWS policy and role to be used in GitHub actions
by assuming the created role with OIDC federation. The GitHub action assumes the
AWS role by authenticating via GitHub OpenID Connect (OIDC) identity provider,
refer [Use IAM roles to connect GitHub Actions to actions in
AWS](https://aws.amazon.com/blogs/security/use-iam-roles-to-connect-github-actions-to-actions-in-aws/).
This can be made easy by using [Configure AWS
Credentials](https://github.com/marketplace/actions/configure-aws-credentials-action-for-github-actions)
GitHub action.

By default, `AWS_ACCOUNT_ID` GitHub actions secret is created. This name is
overridable, see `variables.tf`.

It also supports adding custom secrets and variables in addition to the above.

**NOTE:** Overwriting existing GitHub secrets and variables is not supported.

## Usage

```hcl
module "aws_gh_actions" {
source = "git::https://github.com/fluxcd/test-infra.git//tf-modules/aws/github-actions"
aws_policy_name = "test-policy-1"
aws_policy_description = "For running e2e tests"
aws_provision_perms = [
"ec2:CreateInternetGateway",
"ec2:CreateLaunchTemplate",
"ec2:CreateLaunchTemplateVersion",
]
aws_cluster_role_prefix = [
"flux-test-",
"blue-eks-node-group-",
"green-eks-node-group-"
]
aws_role_name = "test-role-1"
aws_role_description = "Role to be assumed by github actions"
github_repo_owner = "fluxcd"
github_project = "repo-name"
github_repo_branch_ref = "ref:refs/heads/main"
github_variable_custom = {
"SOME_VAR1" = "some-val1",
"SOME_var2" = "some-val2"
}
github_secret_custom = {
"SECRET1" = "some-secret1",
"SECRET2" = "some-secret2"
}
}
```

## AWS Requirements

Use the following IAM policy document to grant the needed permissions.

```json
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "VisualEditor0",
"Effect": "Allow",
"Action": [
"iam:AttachRolePolicy",
"iam:CreatePolicy",
"iam:CreateRole",
"iam:DeletePolicy",
"iam:DeleteRole",
"iam:DetachRolePolicy",
"iam:GetPolicy",
"iam:GetPolicyVersion",
"iam:GetRole",
"iam:ListAttachedRolePolicies",
"iam:ListInstanceProfilesForRole",
"iam:ListPolicyVersions",
"iam:ListRolePolicies"
],
"Resource": "*"
}
]
}
```

Since the GitHub actions use GitHub OIDC identity provider, the AWS account must
have GitHub as an existing identity provider, see [Configuring OpenID Connect in
Amazon Web
Services](https://docs.github.com/en/actions/deployment/security-hardening-your-deployments/configuring-openid-connect-in-amazon-web-services).
The provider URL is expected to be `https://token.actions.githubusercontent.com`
and the audience `sts.amazonaws.com`, as an account can only have a single
instance of this identity provider. These are hard-coded in the configurations
and should be updated in the source, if needed.

## GitHub Requirements

Create a GitHub fine-grained token for the target repository with the following
repository permissions:
- `Read access to metadata`
- `Read and Write access to actions variables and secrets`

## Provider Configuration

Configure the AWS and GitHub provider with the following environment variables:
```sh
export AWS_ACCESS_KEY_ID=""
export AWS_SECRET_ACCESS_KEY=""

export GITHUB_TOKEN=""
```

Check the respective provider docs for more details.
94 changes: 94 additions & 0 deletions tf-modules/aws/github-actions/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
data "aws_caller_identity" "current" {}

locals {
# Set the provider values from input variables and provider configuration.
account_id = var.aws_account_id == "" ? data.aws_caller_identity.current.account_id : var.aws_account_id

# Construct a list of role ARN from the given role prefixes to use in cluster
# permissions below.
clusterperms_resources = [for prefix in var.aws_cluster_role_prefix : "arn:aws:iam::${local.account_id}:role/${prefix}*"]
}

data "aws_iam_policy_document" "policy_doc" {
# Permissions for provisioning the infrastructure.
statement {
sid = "testinfra"
actions = var.aws_provision_perms
resources = ["*"]
}

# Pass cluster permissions to the following roles: cluster, node-groups, etc.
statement {
sid = "clusterperms"
actions = ["iam:PassRole"]
resources = local.clusterperms_resources
}
}

resource "aws_iam_policy" "policy" {
name = var.aws_policy_name
policy = data.aws_iam_policy_document.policy_doc.json
description = var.aws_policy_description
}

# Create assume role policy document for defining the trust relationship with
# GitHub OIDC and the target repository.
data "aws_iam_policy_document" "assume_role_doc" {
statement {
# Create trusted identity of type Web identity with github as the provider.
actions = ["sts:AssumeRoleWithWebIdentity"]
principals {
type = "Federated"
identifiers = ["arn:aws:iam::${local.account_id}:oidc-provider/token.actions.githubusercontent.com"]
}
# Set the audience to STS.
condition {
test = "StringEquals"
variable = "token.actions.githubusercontent.com:aud"
values = ["sts.amazonaws.com"]
}
# Set the GitHub repository.
condition {
test = "StringLike"
variable = "token.actions.githubusercontent.com:sub"
values = ["repo:${var.github_repo_owner}/${var.github_project}:${var.github_repo_branch_ref}"]
}
}
}

# Create a role to assume by github actions.
resource "aws_iam_role" "github_actions_role" {
name = var.aws_role_name
assume_role_policy = data.aws_iam_policy_document.assume_role_doc.json
description = var.aws_role_description
}

# Attach the policy to the role.
resource "aws_iam_role_policy_attachment" "github_actions_role_attachment" {
role = aws_iam_role.github_actions_role.name
policy_arn = aws_iam_policy.policy.arn
}

# Add a GitHub secret variable for the AWS account ID.
resource "github_actions_secret" "account_id" {
repository = var.github_project
secret_name = var.github_secret_accound_id_name
plaintext_value = local.account_id
}

resource "github_actions_variable" "custom" {
for_each = var.github_variable_custom

repository = var.github_project
variable_name = each.key
value = each.value
}

resource "github_actions_secret" "custom" {
# Mark only the key as nonsensitive.
for_each = nonsensitive(toset(keys(var.github_secret_custom)))

repository = var.github_project
secret_name = each.key
plaintext_value = var.github_secret_custom[each.key]
}
72 changes: 72 additions & 0 deletions tf-modules/aws/github-actions/variables.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
variable "aws_account_id" {
description = "AWS account ID"
type = string
default = ""
}

variable "aws_policy_name" {
description = "Name of the policy with all the required permissions"
type = string
}

variable "aws_policy_description" {
description = "IAM policy description"
type = string
}

variable "aws_provision_perms" {
description = "List of permissions for provisioning the infrastructure"
type = list(string)
default = []
}

variable "aws_cluster_role_prefix" {
description = "List of name prefixes of the resources that get cluster permission through IAM pass role"
type = list(string)
default = []
}

variable "aws_role_name" {
description = "Name of the role that will be assumed by the GitHub actions"
type = string
}

variable "aws_role_description" {
description = "IAM role description"
type = string
}

variable "github_repo_owner" {
description = "Name of the GitHub owner (org or user) of the target repository"
type = string
}

variable "github_project" {
description = "Name of the GitHub project where the actions run, and secrets/variables are added"
type = string
}

variable "github_repo_branch_ref" {
description = "Reference to the target branch in the GitHub repository. Use * for any branch"
type = string
default = "ref:refs/heads/main"
}

variable "github_secret_accound_id_name" {
description = "GitHub secret name for AWS accound ID"
type = string
default = "AWS_ACCOUNT_ID"
}

variable "github_variable_custom" {
description = "A map of custom GitHub variables to be created"
type = map(string)
default = {}
}

variable "github_secret_custom" {
description = "A map of custom GitHub secrets to be created"
type = map(string)
default = {}
sensitive = true
}
13 changes: 13 additions & 0 deletions tf-modules/aws/github-actions/versions.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = ">= 5.40"
}

github = {
source = "integrations/github"
version = ">= 6.2"
}
}
}

0 comments on commit 9455a99

Please sign in to comment.