GitHub Action for authenticating to AWS using OIDC (OpenID Connect) or access keys, with optional ECR login and EKS configuration.
- π Secure OIDC Authentication - Recommended passwordless auth
- π Access Key Support - Fallback for environments without OIDC
- π³ ECR Integration - Optional Docker registry login
- βΈοΈ EKS Support - Configure kubectl for your clusters
- π¦ CodeArtifact Support - Configure package managers (npm, pip, etc.)
- π Cross-Account Access - Support for multiple ECR registries
- β Automatic Verification - Confirms successful authentication
name: Deploy to AWS
on: [push]
jobs:
deploy:
runs-on: ubuntu-latest
permissions:
id-token: write # Required for OIDC
contents: read
steps:
- uses: actions/checkout@v4
- name: Login to AWS
uses: KoalaOps/login-aws@v1
with:
role_to_assume: arn:aws:iam::123456789012:role/github-actions
aws_region: us-east-1-
Create an OIDC identity provider in AWS IAM:
- Provider URL:
https://token.actions.githubusercontent.com - Audience:
sts.amazonaws.com
- Provider URL:
-
Create an IAM role with a trust policy:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Federated": "arn:aws:iam::123456789012:oidc-provider/token.actions.githubusercontent.com"
},
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
"StringEquals": {
"token.actions.githubusercontent.com:aud": "sts.amazonaws.com"
},
"StringLike": {
"token.actions.githubusercontent.com:sub": "repo:YourOrg/YourRepo:*"
}
}
}
]
}Use role_to_assume for passwordless authentication via GitHub's OIDC token.
Use aws_access_key_id and aws_secret_access_key for traditional authentication. Only use when OIDC is not available.
| Input | Description | Required | Default |
|---|---|---|---|
aws_region |
AWS region to use | β | - |
| OIDC Authentication | |||
role_to_assume |
ARN of IAM role to assume via OIDC | - | |
role_session_name |
Name for the assumed role session | β | github-actions-{run-id} |
role_duration |
Session duration in seconds | β | 3600 |
| Access Key Authentication | |||
aws_access_key_id |
AWS Access Key ID | - | |
aws_secret_access_key |
AWS Secret Access Key | - | |
| Services | |||
enable_ecr_login |
Enable Docker login to ECR | β | false |
eks_cluster_name |
EKS cluster to configure kubectl for | β | - |
ecr_registries |
AWS account IDs for cross-account ECR access (comma-separated) | β | - |
ecr_repositories |
ECR repository to create if missing (currently limited to single repository) | β | - |
codeartifact_domain |
CodeArtifact domain name | β | - |
codeartifact_repository |
CodeArtifact repository name | β | - |
codeartifact_tool |
Tool to configure (npm, pip, twine, dotnet, nuget, swift, maven, gradle) | β | - |
codeartifact_region |
CodeArtifact region (defaults to aws_region) |
β | - |
codeartifact_domain_owner |
AWS account ID that owns the domain (defaults to authenticated account) | β | - |
codeartifact_duration |
Token duration in seconds | β | 43200 (12 hours) |
codeartifact_namespace |
CodeArtifact namespace for the repository | β | - |
codeartifact_output_token |
Output token as env vars instead of auto-login (useful for Docker builds) | β | false |
*Either use OIDC (role_to_assume) or access keys (aws_access_key_id + aws_secret_access_key)
| Task | Required Inputs | Optional Inputs |
|---|---|---|
| EKS only | aws_region, eks_cluster_name, auth* |
- |
| ECR only | aws_region, enable_ecr_login: true, auth* |
ecr_repositories, ecr_registries |
| CodeArtifact only | aws_region, codeartifact_domain, codeartifact_repository, codeartifact_tool, auth* |
codeartifact_region, codeartifact_domain_owner, codeartifact_duration |
| Both EKS & ECR | aws_region, eks_cluster_name, enable_ecr_login: true, auth* |
ecr_repositories, ecr_registries |
| Cross-account ECR | aws_region, enable_ecr_login: true, ecr_registries, auth* |
- |
*auth = either role_to_assume (OIDC) or aws_access_key_id + aws_secret_access_key
| Output | Description |
|---|---|
aws_account_id |
AWS Account ID |
ecr_registry |
ECR registry URL (if ECR login enabled) |
ecr_logged_in |
true if ECR login was performed, false otherwise |
kubectl_context |
Kubernetes context name (if EKS configured) |
codeartifact_logged_in |
true if CodeArtifact login was performed, false otherwise |
codeartifact_endpoint |
CodeArtifact repository endpoint URL (set when using token-based auth) |
Note: When using token-based authentication (Maven/Gradle or when codeartifact_output_token: 'true'), the authorization token is available via the CODEARTIFACT_AUTH_TOKEN environment variable. For security reasons, the token is not exposed as an output, only as a masked environment variable.
Use when you need to access ECR registries in other AWS accounts:
- Pulling base images from a shared account
- Pushing to a central registry account
- Multi-account deployment pipelines
Format: Comma-separated AWS account IDs
Example: ecr_registries: "123456789012,987654321098"
Use when you want to ensure a repository exists in your account:
- Auto-creating a repo for a new service
- CI/CD pipelines that may run before infrastructure setup
- Avoiding "repository not found" errors
Example: ecr_repositories: "my-app"
Note: Currently limited to a single repository. For multiple repositories, run the action multiple times or create them separately.
Note: These can be used together - ecr_registries for cross-account access, ecr_repositories for repo creation.
CodeArtifact supports multiple package managers:
- npm - Node.js package manager
- pip - Python package installer
- twine - Python package uploader
- dotnet - .NET package manager
- nuget - NuGet package manager
- swift - Swift package manager
- maven - Java/JVM package manager (token-based auth)
- gradle - Java/JVM build tool (token-based auth)
Note: For Maven and Gradle, this action always uses token-based authentication and exports environment variables (CODEARTIFACT_AUTH_TOKEN and CODEARTIFACT_REPO_URL) that you'll reference in your configuration files, since the AWS CLI login command doesn't support these tools natively.
By default, this action uses the simple aws codeartifact login command for npm, pip, twine, dotnet, nuget, and swift. This modifies local configuration files (e.g., ~/.npmrc for npm).
However, if you need the token explicitly (such as for Docker builds where local config isn't available), set codeartifact_output_token: 'true'. This will:
- Export
CODEARTIFACT_AUTH_TOKENas a masked environment variable - Export
CODEARTIFACT_REPO_URLas an environment variable - Set
codeartifact_endpointoutput for easy access
When to use token mode:
- Docker builds that need to install packages inside containers
- Custom authentication flows
- Multi-stage builds where config files don't persist
- When you need to pass credentials as build arguments
To enable CodeArtifact login, you must provide:
codeartifact_domain- Your CodeArtifact domain namecodeartifact_repository- The repository within the domaincodeartifact_tool- Which package manager to configure
codeartifact_region- Defaults to the mainaws_regioninputcodeartifact_domain_owner- Defaults to the authenticated AWS accountcodeartifact_duration- Token lifetime in seconds (default: 43200 = 12 hours)codeartifact_namespace- Namespace for the repository (e.g.,com.mycompanyfor Maven,my-orgfor npm)
For cross-account CodeArtifact access, specify the codeartifact_domain_owner parameter with the AWS account ID that owns the domain.
- name: Login to AWS with access keys
uses: KoalaOps/login-aws@v1
with:
aws_access_key_id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws_secret_access_key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws_region: us-east-1
enable_ecr_login: true- name: Login to AWS with ECR
uses: KoalaOps/login-aws@v1
with:
role_to_assume: ${{ secrets.AWS_ROLE_ARN }}
aws_region: us-east-1
enable_ecr_login: true
ecr_repositories: my-app # Optional: ensures repository exists
- name: Build and push Docker image
run: |
docker build -t ${{ steps.login-aws.outputs.ecr_registry }}/my-app:latest .
docker push ${{ steps.login-aws.outputs.ecr_registry }}/my-app:latest- name: Login and setup ECR repo
uses: KoalaOps/login-aws@v1
with:
role_to_assume: ${{ secrets.AWS_ROLE_ARN }}
aws_region: us-east-1
enable_ecr_login: true
ecr_repositories: backend # Currently limited to single repository- name: Login to AWS with EKS
uses: KoalaOps/login-aws@v1
with:
role_to_assume: ${{ secrets.AWS_ROLE_ARN }}
aws_region: us-east-1
eks_cluster_name: production-cluster
- name: Deploy to Kubernetes
run: |
kubectl apply -f k8s/deployment.yaml
kubectl rollout status deployment/my-app- name: Login to AWS with multiple ECR registries
id: aws
uses: KoalaOps/login-aws@v1
with:
role_to_assume: ${{ secrets.AWS_ROLE_ARN }}
aws_region: us-east-1
enable_ecr_login: true
ecr_registries: "123456789012,987654321098" # AWS Account IDs
- name: Push to multiple registries
run: |
# Build image
docker build -t my-app:latest .
# Push to primary account
docker tag my-app:latest 123456789012.dkr.ecr.us-east-1.amazonaws.com/my-app:latest
docker push 123456789012.dkr.ecr.us-east-1.amazonaws.com/my-app:latest
# Push to secondary account
docker tag my-app:latest 987654321098.dkr.ecr.us-east-1.amazonaws.com/shared/my-app:latest
docker push 987654321098.dkr.ecr.us-east-1.amazonaws.com/shared/my-app:latest- name: Login to AWS with CodeArtifact
uses: KoalaOps/login-aws@v1
with:
role_to_assume: ${{ secrets.AWS_ROLE_ARN }}
aws_region: us-east-1
codeartifact_domain: my-artifacts
codeartifact_repository: npm-store
codeartifact_tool: npm
codeartifact_namespace: my-org # Optional: specify namespace
- name: Install dependencies
run: npm install
- name: Publish package
run: npm publish- name: Login to AWS with CodeArtifact
uses: KoalaOps/login-aws@v1
with:
role_to_assume: ${{ secrets.AWS_ROLE_ARN }}
aws_region: us-east-1
codeartifact_domain: my-artifacts
codeartifact_repository: pypi-store
codeartifact_tool: pip
codeartifact_namespace: my-org # Optional: specify namespace
- name: Install dependencies
run: pip install -r requirements.txt
- name: Build and publish
run: |
python -m build
twine upload dist/*- name: Login to AWS with cross-account CodeArtifact
uses: KoalaOps/login-aws@v1
with:
role_to_assume: ${{ secrets.AWS_ROLE_ARN }}
aws_region: us-east-1
codeartifact_domain: shared-artifacts
codeartifact_domain_owner: "123456789012" # Different account
codeartifact_repository: npm-shared
codeartifact_tool: npm
codeartifact_namespace: shared-org # Optional: specify namespace
codeartifact_duration: 43200 # 12 hours- name: Login to AWS with CodeArtifact
uses: KoalaOps/login-aws@v1
with:
role_to_assume: ${{ secrets.AWS_ROLE_ARN }}
aws_region: us-east-1
codeartifact_domain: my-artifacts
codeartifact_repository: maven-repo
codeartifact_tool: maven
codeartifact_namespace: com.mycompany # Optional: specify namespace
- name: Build with Maven
run: mvn clean install
- name: Publish to CodeArtifact
run: mvn deployRequired ~/.m2/settings.xml configuration:
<settings>
<servers>
<server>
<id>codeartifact</id>
<username>aws</username>
<password>${env.CODEARTIFACT_AUTH_TOKEN}</password>
</server>
</servers>
<profiles>
<profile>
<id>codeartifact</id>
<repositories>
<repository>
<id>codeartifact</id>
<url>${env.CODEARTIFACT_REPO_URL}</url>
</repository>
</repositories>
</profile>
</profiles>
<activeProfiles>
<activeProfile>codeartifact</activeProfile>
</activeProfiles>
</settings>For publishing packages, add to your pom.xml:
<distributionManagement>
<repository>
<id>codeartifact</id>
<url>${env.CODEARTIFACT_REPO_URL}</url>
</repository>
</distributionManagement>Important: The <id> in distributionManagement must match the <server><id> in settings.xml for authentication to work.
Alternatively, you can create the settings.xml in your workflow:
- name: Login to AWS with CodeArtifact
uses: KoalaOps/login-aws@v1
with:
role_to_assume: ${{ secrets.AWS_ROLE_ARN }}
aws_region: us-east-1
codeartifact_domain: my-artifacts
codeartifact_repository: maven-repo
codeartifact_tool: maven
- name: Create Maven settings.xml
run: |
mkdir -p ~/.m2
cat > ~/.m2/settings.xml << 'EOF'
<settings>
<servers>
<server>
<id>codeartifact</id>
<username>aws</username>
<password>${env.CODEARTIFACT_AUTH_TOKEN}</password>
</server>
</servers>
<profiles>
<profile>
<id>codeartifact</id>
<repositories>
<repository>
<id>codeartifact</id>
<url>${env.CODEARTIFACT_REPO_URL}</url>
</repository>
</repositories>
</profile>
</profiles>
<activeProfiles>
<activeProfile>codeartifact</activeProfile>
</activeProfiles>
</settings>
EOF
- name: Build and deploy
run: mvn clean deploy- name: Login to AWS with CodeArtifact
uses: KoalaOps/login-aws@v1
with:
role_to_assume: ${{ secrets.AWS_ROLE_ARN }}
aws_region: us-east-1
codeartifact_domain: my-artifacts
codeartifact_repository: maven-repo
codeartifact_tool: gradle
codeartifact_namespace: com.mycompany # Optional: specify namespace
- name: Build with Gradle
run: ./gradlew build
- name: Publish to CodeArtifact
run: ./gradlew publishWhen building Docker images that need to install packages from CodeArtifact, you need to use token mode:
- name: Login to AWS with CodeArtifact (token mode)
id: aws
uses: KoalaOps/login-aws@v1
with:
role_to_assume: ${{ secrets.AWS_ROLE_ARN }}
aws_region: us-east-1
codeartifact_domain: my-artifacts
codeartifact_repository: npm-store
codeartifact_tool: npm
codeartifact_namespace: my-org # Optional: specify namespace
codeartifact_output_token: 'true' # Enable token mode
enable_ecr_login: true
- name: Build Docker image with CodeArtifact access
run: |
docker build \
--build-arg CODEARTIFACT_AUTH_TOKEN=${{ env.CODEARTIFACT_AUTH_TOKEN }} \
--build-arg CODEARTIFACT_REPO_URL=${{ env.CODEARTIFACT_REPO_URL }} \
-t my-app:latest \
.
- name: Push to ECR
run: |
docker tag my-app:latest ${{ steps.aws.outputs.ecr_registry }}/my-app:latest
docker push ${{ steps.aws.outputs.ecr_registry }}/my-app:latestDockerfile example for npm:
FROM node:18-alpine
ARG CODEARTIFACT_AUTH_TOKEN
ARG CODEARTIFACT_REPO_URL
WORKDIR /app
# Configure npm to use CodeArtifact
RUN npm config set registry ${CODEARTIFACT_REPO_URL}
RUN echo "${CODEARTIFACT_REPO_URL#https:}:_authToken=${CODEARTIFACT_AUTH_TOKEN}" > .npmrc
# Install dependencies
COPY package*.json ./
RUN npm install
# Copy application code
COPY . .
# Build application
RUN npm run build
CMD ["npm", "start"]Dockerfile example for Python/pip:
FROM python:3.11-slim
ARG CODEARTIFACT_AUTH_TOKEN
ARG CODEARTIFACT_REPO_URL
WORKDIR /app
# Configure pip to use CodeArtifact
RUN pip config set global.index-url https://aws:${CODEARTIFACT_AUTH_TOKEN}@${CODEARTIFACT_REPO_URL#https://}simple/
# Install dependencies
COPY requirements.txt ./
RUN pip install -r requirements.txt
# Copy application code
COPY . .
CMD ["python", "app.py"]Required build.gradle configuration:
repositories {
maven {
url System.env.CODEARTIFACT_REPO_URL
credentials {
username "aws"
password System.env.CODEARTIFACT_AUTH_TOKEN
}
}
}
publishing {
repositories {
maven {
url System.env.CODEARTIFACT_REPO_URL
credentials {
username "aws"
password System.env.CODEARTIFACT_AUTH_TOKEN
}
}
}
}Or for Kotlin DSL (build.gradle.kts):
repositories {
maven {
url = uri(System.getenv("CODEARTIFACT_REPO_URL") ?: "")
credentials {
username = "aws"
password = System.getenv("CODEARTIFACT_AUTH_TOKEN") ?: ""
}
}
}
publishing {
repositories {
maven {
url = uri(System.getenv("CODEARTIFACT_REPO_URL") ?: "")
credentials {
username = "aws"
password = System.getenv("CODEARTIFACT_AUTH_TOKEN") ?: ""
}
}
}
}- name: Login to AWS for long operation
uses: KoalaOps/login-aws@v1
with:
role_to_assume: ${{ secrets.AWS_ROLE_ARN }}
aws_region: us-east-1
role_duration: 7200 # 2 hoursThis action internally uses:
aws-actions/configure-aws-credentials@v4- AWS OIDC authenticationaws-actions/amazon-ecr-login@v2- ECR Docker loginKoalaOps/ensure-ecr-repository@v1- ECR repository creation (when ecr_repositories provided)
- Use OIDC - Never store AWS access keys as secrets
- Least Privilege - Grant minimal required permissions to the IAM role
- Restrict Trust Policy - Limit which repositories and branches can assume the role
- Short Sessions - Use the minimum
role_durationneeded
Ensure your repository has the id-token: write permission:
permissions:
id-token: write
contents: readCheck your IAM role's trust policy includes the correct repository pattern:
"StringLike": {
"token.actions.githubusercontent.com:sub": "repo:YourOrg/YourRepo:*"
}Ensure the IAM role has the necessary ECR permissions:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"ecr:GetAuthorizationToken",
"ecr:BatchCheckLayerAvailability",
"ecr:GetDownloadUrlForLayer",
"ecr:BatchGetImage"
],
"Resource": "*"
},
{
"Effect": "Allow",
"Action": [
"ecr:PutImage",
"ecr:InitiateLayerUpload",
"ecr:UploadLayerPart",
"ecr:CompleteLayerUpload"
],
"Resource": "arn:aws:ecr:*:*:repository/*"
}
]
}For repository creation (ecr_repositories), add:
{
"Effect": "Allow",
"Action": [
"ecr:CreateRepository",
"ecr:DescribeRepositories"
],
"Resource": "*"
}Ensure the IAM role has the necessary EKS permissions:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"eks:DescribeCluster",
"eks:ListClusters"
],
"Resource": "*"
}
]
}Note: You also need to be mapped in the EKS cluster's aws-auth ConfigMap or use EKS access entries.
Ensure the IAM role has the necessary CodeArtifact permissions:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"codeartifact:GetAuthorizationToken",
"codeartifact:GetRepositoryEndpoint",
"codeartifact:ReadFromRepository"
],
"Resource": "*"
},
{
"Effect": "Allow",
"Action": "sts:GetServiceBearerToken",
"Resource": "*",
"Condition": {
"StringEquals": {
"sts:AWSServiceName": "codeartifact.amazonaws.com"
}
}
}
]
}For publishing packages, add:
{
"Effect": "Allow",
"Action": [
"codeartifact:PublishPackageVersion",
"codeartifact:PutPackageMetadata"
],
"Resource": "*"
}- π Documentation
- π Issue Tracker
- π¬ Discussions
MIT