일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 | 29 |
30 | 31 |
- 보안 규칙
- gcp
- Uptime Check
- Clean Code
- interconnect
- VAGRANT
- Python
- github
- cloud
- devops
- IAM
- cicd
- Google Cloud Platform
- cloud armor
- kubernetes
- 후기
- Terraform Cloud
- terraform
- AWS
- CentOS
- vpc peering
- direnv
- MIG
- docker
- cloud function
- pub/sub
- vm
- 우테캠
- 자격증
- Java
- Today
- Total
EMD Blog
Github Actions에서 OIDC를 통해 AWS에 액세스 본문
OIDC란 Open ID Connect의 약자로 일종의 인증 프로토콜이다. 이와 관련된 문서들을 보면 매커니즘이 OAuth2.0과 매우 비슷하다는 느낌을 받을 수 있는데 이는 OIDC가 OAuth2.0을 기반으로 하기 때문이다.
자세한 설명은 아래 문서 참고.
Github Actions에서 AWS에 접근하고자 할 때 AWS인증과 권한을 필요로 한다. 예를 들면 파이프라인에서 S3에 파일을 업로드 할 때나 ECR Private Repository Push 할 때가 그렇다.
이때 Github Actions에서는 다음처럼 인증을 수행할 수 있다. (repository)
- name: Configure AWS Credentials
uses: aws-actions/configure-aws-credentials@v1
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: us-east-2
위 방식은 AWS에서 적절한 권한이 포함된 IAM User를 생성한 뒤 액세스 키를 받아 Github Actions에 secret으로 등록하고 사용하는 방식이다.
물론 이렇게 직접 키를 등록해도 되겠지만 OIDC를 사용해 인증하는 방법을 사용할 수도 있다.
OIDC를 사용했을 때의 이점은 아래 문서를 통해 확인할 수 있다.
요약하면 다음과 같다.
- 직접 키를 관리하지 않아 관리에 용이
- AWS 리소스 접근제어를 보다 세부적으로 제어 가능
- 단기 토큰을 발행하기 때문에 보안적으로 우수
OIDC를 통해 인증을 하기 위해서는 크게 3가지 작업이 필요하다.
- AWS에 자격 증명 공급자에 OpenID Connect 타입으로 Github OIDC Provider를 등록
- 신뢰정책을 생성 - 보안주체로 Github OIDC Provider 지정 및 Repository 필터링
- 위 신뢰정책을 사용해 역할 생성 후 적절한 권한이 포함된 정책 지정
위 작업을 진행하면 Github Actions에서는 aws-actions/configure-aws-credentials를 사용해 단기 클라우드 액세스 토큰을 얻을 수 있다.
이 OIDC를 사용한 인증 과정은 다음과 같이 요약 가능하다.
- 정확하게는 Actions에서 Github OIDC Provider에 토큰을 요청하고 그 토큰을 받아 AWS에 전달
- AWS 신뢰정책을 통해 해당 토큰을 검증
- 검증 성공 시 단기 액세스 토큰을 발행
이때 토큰은 JWT으로 발행되며 안에 포함된 클레임은 아래 링크에서 상세하게 확인할 수 있다.
이제 동작 과정과 토큰 내용을 확인했으니 실제로 구성해보자.
먼저 AWS 자격 증명 공급자에 OpenID Connect 타입으로 Github OIDC Provider를 등록한다.
이때, 아래 문서들을 보면 발행자(iss)와 지문이 필요한 것을 알 수 있다.
https://docs.aws.amazon.com/cli/latest/reference/iam/create-open-id-connect-provider.html
iss의 아래 링크에 보면 iss를 확인할 수 있다.
https://token.actions.githubusercontent.com
하지만 지문의 경우 직접 확인을 해야하는데 이에 대한 내용은 아래 문서에서 확인할 수 있다.
문서를 보면 지문이란 것이 필요한 이유에 대해 설명해주고 있는데, 자격 증명 공급자를 생성할 때 등록하는 지문은 OIDC Provider가 사용하는 인증서의 인증기관에 대한 지문이며 이 지문을 통해 OIDC Provider의 인증서를 신뢰하게 된다.
Github OIDC Provider의 경우 인터넷에 쳐도 바로 나오긴한다. 하지만 최신화되어 있지 않을 수도 있기 때문에 아래 과정을 통해 얻는 것을 추천.
먼저 https://token.actions.githubusercontent.com/.well-known/openid-configuration에서 jwks_uri값을 찾는다.
$ curl https://token.actions.githubusercontent.com/.well-known/openid-configuration
{
"issuer":"https://token.actions.githubusercontent.com",
"jwks_uri":"https://token.actions.githubusercontent.com/.well-known/jwks",
"subject_types_supported":["public","pairwise"],
...
}
여기서 jwks_uri의 도메인만 복사해 아래처럼 인증서를 출력시킨다. (지금은 iss와 동일)
$ openssl s_client -servername token.actions.githubusercontent.com -showcerts -connect token.actions.githubusercontent.com:443
...
-----BEGIN CERTIFICATE-----
MIIG8jCCBdqgAwIBAgIQCn5zvdee2Vg6XXlzFLM1XDANBgkqhkiG9w0BAQsFADBP
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMSkwJwYDVQQDEyBE
aWdpQ2VydCBUTFMgUlNBIFNIQTI1NiAyMDIwIENBMTAeFw0yMjExMDQwMDAwMDBa
Fw0yMzExMDcy
...
uJ5ZrAXfh48ZtVq/qmjfCX7f0ntUcsm85S2oNKAaKqqlGuwjA7ye80O3WHKQLXXM
evZ35QEWOlwhphLyHhUL6QFCuAe0wL2arESMXnxgaYE7Ka+SexxEiT5ZmdyrcFwg
BL7FKjOM
-----END CERTIFICATE-----
...
-----BEGIN CERTIFICATE-----
MIIE6jCCA9KgAwIBAgIQCjUI1VwpKwF9+K1lwA/35DANBgkqhkiG9w0BAQsFADBh
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD
...
g0qZgYOrAKHKCjxMoiWJKiKnpPMzTFuMLhoClw+dj20tlQj7T9rxkTgl4ZxuYRiH
as6xuwAwapu3r9rxxZf+ingkquqTgLozZXq8oXfpf2kUCwA/d5KxTVtzhwoT0JzI
8ks5T1KESaZMkE4f97Q=
-----END CERTIFICATE-----
...
출력시키면 위처럼 2가지 인증서가 출력되는데 이 중 아래 인증서를 전부 복사해 certificate.crt라는 이름으로 저장한다.
(-----BEGIN CERTIFICATE----- , -----END CERTIFICATE-----포함)
그 다음 아래 명령어로 지문을 출력하면 된다.
$ openssl x509 -in certificate.crt -fingerprint -sha1 -noout | sed -e 's/://g' | tr '[:upper:]' '[:lower:]'
sha1 fingerprint=6938fd4d98bab03faadb97b34396831e3780aea1
이제 아래처럼 OIDC Provider를 등록할 수 있다.
$ aws iam create-open-id-connect-provider \\
--url <https://token.actions.githubusercontent.com> \\
--thumbprint-list 6938fd4d98bab03faadb97b34396831e3780aea1
자격증명 공급자를 등록했으니 이제 신뢰정책을 생성해야 한다.
신뢰정책을 구성하는 방법은 아래 문서에서 친절하게 안내해주고 있다.
신뢰정책은 아래처럼 구성한다. 이 신뢰정책은 역할 생성시 json 형식으로 지정해주어야하기 때문에 json 파일로 생성한다.
$ cat > github-oidc-trust-policy.json << EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Federated": "arn:aws:iam::<aws_account_number>:oidc-provider/token.actions.githubusercontent.com"
},
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
"StringLike": {
"token.actions.githubusercontent.com:sub": "repo:<user or organization>/<repository name>:*"
},
"StringEquals": {
"token.actions.githubusercontent.com:aud": "sts.amazonaws.com"
}
}
}
]
}
EOF
(<user or organization>/<repository name> 값은 Actions를 수행하는 자신의 repository 정보로 바꿔주자)
보안 주체(Principal)로 이전에 등록한 Github OIDC Provider ARN을 지정해주고 Actions으로 AssumRoleWithWebIdentity를 지정해주었다. AssumRole은 AWS 리소스에 액세스하기 위해 임시 자격증명을 얻는 작업인데, WithWebIdentity가 붙으면 웹 자격 증명 공급자를 통해 임시 보안 자격 증명을 얻을 수 있다.
그렇다면 위 신뢰정책은 보안주체인 Github OIDC Provider에 대해서 웹 자격 증명을 통한 AWS 리소스 액세스를 허용하겠다는 뜻인데, 저 보안 주체는 너무 광범위 하다.
이전에 GIthub OIDC Provider가 반환하는 토큰(JWT)을 통해 신뢰 관계를 검증한다고 했는데 이 JWT 클레임을 검증해서 신뢰할 수 있는 요청인지 확인할 수 있다.
검증은 위 신뢰정책에서 Condition(조건)에 해당하는 부분인데 내용을 보면 다음과 같다.
- token.actions.githubusercontent.com:sub 값에 repo:<user or organization>/<repository name>:가 포함되어 있는지?
- token.actions.githubusercontent.com:aud 값이 sts.amazonaws.com 인지?
그리고 각 값을 살펴보면 다음과 같다.
sub: subject의 약자로 JWT에는 이 토큰을 전달한 repository 정보가 담겨있다.
aud: audience의 약자로 요청할 대상을 말한다. 이 문서를 보면 STS 요청은 https://sts.amazonaws.com이라는 단일 엔드포인트만 제공하고 있다. 왜 STS 요청이냐하면 AssumRoleWithWebIdentity가 STS의 API이기 때문.
위 값을 외에도 다른 클레임으로 조건을 작성할 수 있다. 클레임에 포함된 전체 내용은 아래 문서를 참고.
정리하면 위 신뢰정책의 내용은 다음과 같이 요약할 수 있다.
“이 정책은 보안주체인 Github OIDC Provider에 대해서 웹 자격 증명을 통한 AWS 리소스 액세스를 허용하지만 모든 요청에 대해 액세스를 허용하지 않고 repo:<user or organization>/<repository name> repository에서 sts.amazonaws.com로 요청한 건에 대해서만 허용해주겠다.”
이제 이 신뢰 정책으로 역할을 생성하자.
$ aws iam create-role \\
--role-name GithubOIDCRole \\
--assume-role-policy-document file://github-oidc-trust-policy.json
이제 임시보안자격증명을 얻을 수 있게 되었다. 하지만 이는 IAM 권한을 활용하기 위한 초기 설정일 뿐이다. 이 보안자격증명으로 필요한 AWS 리소스에 액세스 할 수 있도록 권한을 설정해야 한다.
권한 부여를 위해 정책을 하나 생성한다. 권한은 본인이 필요한 권한을 부여하면 된다. 지금은 ECR에 Push한다고 생각하고 아래처럼 권한을 지정했다. (ECR 이미지 Push에 대한 최소권한은 이 문서를 참고.)
cat > ecr-push-policy.json << EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"ecr:CompleteLayerUpload",
"ecr:UploadLayerPart",
"ecr:InitiateLayerUpload",
"ecr:BatchCheckLayerAvailability",
"ecr:PutImage"
],
"Resource": "arn:aws:ecr:<region>:<aws_account_number>:repository/<repository_name>"
},
{
"Effect": "Allow",
"Action": "ecr:GetAuthorizationToken",
"Resource": "*"
}
]
}
EOF
$ aws iam create-policy \\
--policy-name ECRPush \\
--policy-document file://ecr-push-policy.json
policy를 생성했으면 이전에 만든 GithubOIDCRole에 붙여주자.
$ aws iam attach-role-policy \\
--role-name GithubOIDCRole \\
--policy-arn arn:aws:iam::<aws_account_number>:policy/ECRPush
이제 역할이 준비되었으니 Github Actions에서 이 역할을 사용하도록 지정한다.
인증에 사용될 라이브러리(action)는 aws-actions/configure-aws-credentials이다.
제일 먼저 할 것은 Github OIDC Provider로 부터 JWT(AWS로 전달할 토큰)를 받을 수 있게 권한을 설정하는 것이다.
permissions:
id-token: write
contents: read
그 다음 AWS 인증을 통해 임시보안자격증명을 획득한다.
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v1
with:
role-to-assume: arn:aws:iam::<aws_account_number>:role/GithubOIDCRole
aws-region: ap-northeast-2
별다른 내용이 없는데 인증 자체를 role에 포함된 신뢰정책으로 하기 때문이다. role만 잘 지정해주자.
여기까지하면 AWS 인증은 끝이다. 만약 ECR Push도 하고 싶다면 아래 action을 사용하면 된다.
전체 샘플 코드는 다음과 같다.
name: "Continuous Integration - Spring App"
on:
push:
branches:
- main
jobs:
code-build:
runs-on: ubuntu-22.04
permissions:
id-token: write
contents: read
needs: code-tests
steps:
- uses: actions/checkout@v3
- uses: actions/setup-java@v3
with:
distribution: 'zulu'
java-version: '8'
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v1
with:
role-to-assume: arn:aws:iam::<aws_account_number>:role/GithubOIDCRole
aws-region: ap-northeast-2
- name: Login to Amazon ECR
id: login-ecr
uses: aws-actions/amazon-ecr-login@v1
- name: Build and push docker image to Amazon ECR
env:
REGISTRY: ${{ steps.login-ecr.outputs.registry }}
REPOSITORY: test-api
IMAGE_TAG: ${{ github.sha }}
run: |
./gradlew bootBuildImage --imageName=$REGISTRY/$REPOSITORY:$IMAGE_TAG
docker tag $REGISTRY/$REPOSITORY:$IMAGE_TAG $REGISTRY/$REPOSITORY:latest
docker push $REGISTRY/$REPOSITORY:$IMAGE_TAG
docker push $REGISTRY/$REPOSITORY:latest
'Public Cloud > AWS' 카테고리의 다른 글
[후기] AWS Certified Solutions Architect - Professional (SAP-C02) 취득 (2) | 2024.07.13 |
---|---|
[후기] AWS Certified DevOps Engineer - Professional (DOP-C02) 취득 (0) | 2024.07.13 |
ALB와 CloudFront를 사용할 때 VirtualHost 사용 테스트 (0) | 2022.12.27 |
EKS에서 Cluster의 IAM role과 Service account IAM role (0) | 2022.12.19 |
Bastion Host를 통한 RDS SQL Server 접속 (0) | 2022.10.22 |