DEV Community

Cover image for GitHub Actions autenticando na AWS via OIDC
Mateus Miranda
Mateus Miranda

Posted on

GitHub Actions autenticando na AWS via OIDC

O GitHub recentemente lançou uma funcionalidade para fazer autenticação via OIDC na AWS de dentro dos workflows, dando a oportunidade de se livrar de uma vez por todas do gerenciamento de um usuário específico para isso.

Basicamente, a autenticação agora ocorre via OIDC e a única coisa que você precisa para isso é informar qual a role vai ser utilizada.

Neste artigo, iremos realizar toda a configuração necessária na AWS via Terraform, e claro, ver como isso funciona.

Terraform

A configuração via Terraform é relativamente simples e não exige muito conhecimento avançado.

Vamos começar criando o nosso oidc provider:

resource "aws_iam_openid_connect_provider" "github" {
  url             = "https://token.actions.githubusercontent.com"
  client_id_list  = ["sts.amazonaws.com"]
  thumbprint_list = ["a031c46782e6e6c662c2c87c76da9aa62ccabd8e"]
}
Enter fullscreen mode Exit fullscreen mode

Tanto a informação de url quanto client_id_list são fornecidas pelo GitHub na própria documentação deles, que você pode ler aqui.

Já o thumbprint_list foi mais chato de entender pois ele é gerado baseado na chave ssl do certificado da configuração do openid do GitHub. O que importa aqui é: esse valor é baseado na url, então ele é estático e você pode apenas copiar e colar sem medo.

Mas caso você queira ir fundo nesse tópico, leia um pouco Como Obter a impressão digital da CA raiz para um provedor de identidade OpenID Connect.

O próximo passo é criar o nosso policy document, dando permissão para os repositórios fazerem assume role:

data "aws_iam_policy_document" "github_actions_assume_role" {
  statement {
    actions = ["sts:AssumeRoleWithWebIdentity"]
    principals {
      type        = "Federated"
      identifiers = [aws_iam_openid_connect_provider.github.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:org1/*:*",
        "repo:org2/*:*"
      ]
    }
  }
Enter fullscreen mode Exit fullscreen mode

No exemplo acima, qualquer repositório da org1 ou org2 terão permissão sts:AssumeRoleWithWebIdentity e consequentemente, assumir a nossa role que vamos criar.

É possível restringir essa permissão para alguns repositórios (e até mesmo branches específicos), para isso basta alterar a sua condition para:

    condition {
      test     = "StringLike"
      variable = "token.actions.githubusercontent.com:sub"
      values = [
        "repo:org/meu-repositorio:*",
      ]
    }
Enter fullscreen mode Exit fullscreen mode

Outro ponto importante a ser notado, é que o valor de token.actions.githubusercontent.com:aud foi colocado como sts.amazonaws.com e não como https://github.com/org como específicado na documentação. do GitHub.

Seguindo no nosso tutorial, agora precisamos criar a nossa role de fato e associá-la ao documento previamente criado:

resource "aws_iam_role" "github_actions" {
  name               = "github-actions"
  assume_role_policy = data.aws_iam_policy_document.github_actions_assume_role.json
}
Enter fullscreen mode Exit fullscreen mode

Agora precisamos criar um outro documento de policy, dessa vez com as permissões que a nossa role terá.

Neste caso, iremos ter permissão para realizar algumas operações no nosso ECR, respeitando a única regra de que esse repositório tenha uma tag permit-github-action=true

data "aws_iam_policy_document" "github_actions" {
  statement {
    actions = [
      "ecr:BatchGetImage",
      "ecr:BatchCheckLayerAvailability",
      "ecr:CompleteLayerUpload",
      "ecr:GetDownloadUrlForLayer",
      "ecr:InitiateLayerUpload",
      "ecr:PutImage",
      "ecr:UploadLayerPart",
    ]
    resources = ["*"]
    condition {
      test     = "StringEquals"
      variable = "aws:ResourceTag/permit-github-action"

      values = ["true"]
    }
  }
Enter fullscreen mode Exit fullscreen mode

Reparem que no nosso exemplo estamos utilizando apenas ECR, mas nada impede que você conceda permissão para outros serviços dentro da AWS: S3, SQS, etc.

E por fim, precisamos criar a nossa policy baseada no documento que criamos e depois anexar ela à nossa role:

resource "aws_iam_policy" "github_actions" {
  name        = "github-actions"
  description = "Grant Github Actions the ability to push to ECR"
  policy      = data.aws_iam_policy_document.github_actions.json
}

resource "aws_iam_role_policy_attachment" "github_actions" {
  role       = aws_iam_role.github_actions.name
  policy_arn = aws_iam_policy.github_actions.arn
}
Enter fullscreen mode Exit fullscreen mode

Para finalizar o nosso exemplo, vamos criar um repositório e colocar uma tag nele:

resource "aws_ecr_repository" "repo" {
  name                 = "meu/repositorio"
  image_tag_mutability = "IMMUTABLE"

  image_scanning_configuration {
    scan_on_push = true
  }

  tag = {
    "permit-github-action" = true
  }
}
Enter fullscreen mode Exit fullscreen mode

Github Actions

Basicamente, a configuração do lado do Github Actions é bem simples e não demanda muita mudança se você já está usando via access key e secret key

A primeira coisa que você precisa configurar, segundo a própria documentação do GitHub são as permissões:

    permissions:
      id-token: write
      contents: read
Enter fullscreen mode Exit fullscreen mode

E depois, na actions para configurar as credenciais, informar qual a role vai ser utilizada (a que criamos anteriormente via terraform)

      - name: Configure AWS credentials
        uses: aws-actions/configure-aws-credentials@master
        with:
          role-to-assume: arn:aws:iam::XXXXXXXXXXXX:role/github-actions
          aws-region: eu-west-1

      - name: Login to Amazon ECR
        id: login-ecr
        uses: aws-actions/amazon-ecr-login@v1
Enter fullscreen mode Exit fullscreen mode

Aqui você pode ver o conteúdo final do arquivo YAML.

name: Continuous Delivery

on: [push, pull_request]

jobs:
  build-and-push:
    runs-on: ubuntu-latest

    permissions:
      id-token: write
      contents: read

    steps:
      - name: Configure AWS credentials
        uses: aws-actions/configure-aws-credentials@master
        with:
          role-to-assume: arn:aws:iam::XXXXXXXXXXXX:role/github-actions
          aws-region: eu-west-1

      - name: Login to Amazon ECR
        id: login-ecr
        uses: aws-actions/amazon-ecr-login@v1

      - name: Checkout
        uses: actions/checkout@v2

      - name: Build, tag, and push image to Amazon ECR
        env:
          ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }}
          ECR_REPOSITORY: meu/repositorio
          IMAGE_TAG: ${{ github.sha }}
        run: |
          docker build -t $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG .
          docker push $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG
Enter fullscreen mode Exit fullscreen mode

Espero que tenham curtido! :)

Discussion (1)

Collapse
rasouza profile image
Rodrigo Souza

Ótimos insights em volta do tema. Congrats!