> ## Documentation Index
> Fetch the complete documentation index at: https://engineering.unkey.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Configuring GitHub OIDC

> GitHub Actions OIDC setup with AWS.

## Methods for getting AWS account IDs

Grab the `Basic ~/.aws/config for AdministratorAccess` from [1password](https://engineering.unkey.com/infrastructure/1password).

## In the management/root account

```
aws iam create-open-id-connect-provider \
  --profile unkey-root-admin \
  --url https://token.actions.githubusercontent.com \
  --client-id-list sts.amazonaws.com \
  --thumbprint-list 6938fd4d98bab03faadb97b34396831e3780aea1
```

To get the ARN for the OIDC provider... (you don't need to do this as it's embedded in the policy below, but it's here for reference)

```
aws iam list-open-id-connect-providers --profile unkey-root-admin --output text --no-cli-pager
```

Create a `github-actions-trust-policy.json` for Github Actions role in the root/management account for the `unkeyed/infra:*` repo for all (`*`) branches. This already has the ARN from the above command in place.

```
cat > github-actions-trust-policy.json <<EOF
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Federated": "$(aws iam list-open-id-connect-providers --profile unkey-root-admin --output text --no-cli-pager --query "OpenIDConnectProviderList[0].Arn")"
      },
      "Action": "sts:AssumeRoleWithWebIdentity",
      "Condition": {
        "StringEquals": {
          "token.actions.githubusercontent.com:aud": "sts.amazonaws.com"
        },
        "StringLike": {
          "token.actions.githubusercontent.com:sub": "repo:unkeyed/infra:*"
        }
      }
    }
  ]
}
EOF
```

Create the role with the trust policy

```
aws iam create-role \
  --profile unkey-root-admin \
  --role-name GitHubActionsOIDCRole \
  --assume-role-policy-document file://github-actions-trust-policy.json
```

Create `cross-account-policy.json`. Note: This renders like it didn't interpolate the `*_ACCOUNT` vars, but `less cross-account-policy.json` will show it correctly.

```
SANDBOX_ACCOUNT=$(aws sts get-caller-identity --profile unkey-sandbox-admin --query Account --output text)
CANARY_ACCOUNT=$(aws sts get-caller-identity --profile unkey-canary-admin --query Account --output text)
PRODUCTION001_ACCOUNT=$(aws sts get-caller-identity --profile unkey-production001-admin --query Account --output text)
cat > cross-account-policy.json <<EOF
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": "sts:AssumeRole",
      "Resource": [
        "arn:aws:iam::${SANDBOX_ACCOUNT}:role/UnkeyPulumiAWSExecutor",
        "arn:aws:iam::${CANARY_ACCOUNT}:role/UnkeyPulumiAWSExecutor",
        "arn:aws:iam::${PRODUCTION001_ACCOUNT}:role/UnkeyPulumiAWSExecutor"
      ]
    },
    {
      "Effect": "Allow",
      "Action": ["ec2:DescribeAvailabilityZones", "ec2:DescribeRegions"],
      "Resource": "*"
    }
  ]
}
EOF
```

Create the policy in the root/management account... grab the ARN once it creates, you'll need it later.

```
aws iam create-policy \
  --profile unkey-root-admin \
  --policy-name CrossAccountAssumeRole \
  --policy-document file://cross-account-policy.json
```

Attach the policy to the Github Actions role thingy

```
aws iam attach-role-policy \
  --profile unkey-root-admin \
  --role-name GitHubActionsOIDCRole \
  --policy-arn "arn:aws:iam::333769656712:policy/CrossAccountAssumeRole"
```

## The Pulumi Executor role

This one is a bit of a doozy... You'll have to do this for EACH account... I've tried to streamline/automate most of it, but be mindful and RTFM closely!

First, get the SSO role ID for `AdministratorAccess` for each account in `{sandbox,canary,production001}`

```
aws iam list-roles \
  --profile unkey-sandbox-admin \
  --query "Roles[?contains(RoleName, 'AWSReservedSSO_AdministratorAccess')].{Arn:Arn}" --output text
```

The one we want is for the `AdministratorAccess` role.. this is what sandbox's role ARN looks like...

```
arn:aws:iam::343218208612:role/aws-reserved/sso.amazonaws.com/AWSReservedSSO_AdministratorAccess_c23a3ed1d84d0d63
```

Now, that needs to added to the `pulumi-executor-<ACCOUNT>-trust-policy.json` we'll create... this policy says that anyone with the `AWSReservedSSO_AdministratorAccess_*` role from `<ACCOUNT_NAME>` and the `GithubActionsOIDCRole` from the root/management account can assume this role.

```
# I'm sorry for this bash...
for account in sandbox canary production001; do
ROLE_ID=$(aws iam list-roles \
  --profile "unkey-${account}-admin" \
  --query "Roles[?contains(RoleName, 'AWSReservedSSO_AdministratorAccess')].{Arn:Arn}" --output text)
cat > "pulumi-executor-${account}-trust-policy.json" <<EOF
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "AWS": [
          "${ROLE_ID}",
          "arn:aws:iam::333769656712:role/GitHubActionsOIDCRole"
        ]
      },
      "Action": "sts:AssumeRole"
    }
  ]
}
EOF
unset ROLE_ID;
done
```

Add the role with the policy to each account...

```
for account in sandbox canary production001; do
aws iam create-role \
  --profile "unkey-${account}-admin" \
  --no-cli-pager \
  --role-name UnkeyPulumiAWSExecutor \
  --assume-role-policy-document file://pulumi-executor-${account}-trust-policy.json
done
```

Create the `unkey-pulumi-policy.json`. (Just once!)

```
cat > unkey-pulumi-policy.json << 'EOF'
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "cloudformation:*",
        "cloudwatch:*",
        "ec2:*",
        "ecr:*",
        "ecs:*",
        "elasticache:*",
        "elasticloadbalancing:*",
        "globalaccelerator:*",
        "iam:AttachRolePolicy",
        "iam:CreateRole",
        "iam:DeleteRole",
        "iam:DeleteRolePolicy",
        "iam:DetachRolePolicy",
        "iam:GetRole",
        "iam:GetRolePolicy",
        "iam:PassRole",
        "iam:PutRolePolicy",
        "iam:ListRolePolicies",
        "iam:ListAttachedRolePolicies",
        "iam:ListInstanceProfilesForRole",
        "kms:*",
        "logs:*",
        "ssm:*"
      ],
      "Resource": "*"
    }
  ]
}
EOF
```

Now add the policy to each account and attach it to the role...

```
for account in sandbox canary production001; do
POLICY_ARN=$(aws iam create-policy \
  --profile "unkey-${account}-admin" \
  --policy-name UnkeyPulumiPolicy \
  --policy-document file://unkey-pulumi-policy.json \
  --query 'Policy.Arn' --output text)

# Attach the policy to the role
aws iam attach-role-policy \
  --profile "unkey-${account}-admin" \
  --no-cli-pager \
  --role-name UnkeyPulumiAWSExecutor \
  --policy-arn "${POLICY_ARN}";
done
```
