-
Notifications
You must be signed in to change notification settings - Fork 176
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Github Actions OIDC IAM Role Trust Relation
- Loading branch information
bcpenta
authored and
bcpenta
committed
Dec 19, 2024
1 parent
188b9bc
commit 2d143c0
Showing
2 changed files
with
239 additions
and
0 deletions.
There are no files selected for viewing
37 changes: 37 additions & 0 deletions
37
policies/aws_iam_policies/aws_iam_role_github_actions_trust.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
def policy(resource): | ||
assume_role_policy = resource.get("AssumeRolePolicyDocument", {}).get("Statement", []) | ||
|
||
# Iterate through each statement in the trust policy | ||
for statement in assume_role_policy: | ||
# Check if the statement allows sts:AssumeRoleWithWebIdentity | ||
if statement.get("Effect") == "Allow" and "sts:AssumeRoleWithWebIdentity" in statement.get("Action", []): | ||
# Validate the Principal | ||
principal = statement.get("Principal", {}).get("Federated") | ||
if not principal: | ||
return False # Invalid Principal | ||
if principal == "*": | ||
return False # Wildcard in Principal is insecure | ||
if "oidc-provider/token.actions.githubusercontent.com" not in principal: | ||
continue # Skip non-GitHub-related Principals | ||
|
||
# Validate the conditions only if the Principal is valid for GitHub Actions | ||
conditions = statement.get("Condition", {}) | ||
|
||
# Check if the aud is correctly set | ||
audience = conditions.get("StringEquals", {}).get("token.actions.githubusercontent.com:aud") | ||
if audience != "sts.amazonaws.com": | ||
return False | ||
|
||
# Check if the sub is properly restricted | ||
subject = conditions.get("StringLike", {}).get("token.actions.githubusercontent.com:sub", "") or \ | ||
conditions.get("StringEquals", {}).get("token.actions.githubusercontent.com:sub", "") | ||
|
||
if not subject.startswith("repo:"): | ||
return False # Ensure sub references a repository | ||
|
||
if "*" in subject and not subject.startswith("repo:org/repo:*"): | ||
return False # Disallow overly permissive wildcards | ||
|
||
return True # Valid GitHub Actions config | ||
|
||
return False # No valid statements found |
202 changes: 202 additions & 0 deletions
202
policies/aws_iam_policies/aws_iam_role_github_actions_trust.yml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,202 @@ | ||
AnalysisType: policy | ||
Filename: aws_iam_role_github_actions_trust.py | ||
PolicyID: "AWS.IAM.Role.GitHubActionsTrust" | ||
DisplayName: "AWS IAM Role Trust Relationship for GitHub Actions" | ||
Enabled: true | ||
ResourceTypes: | ||
- AWS.IAM.Role | ||
Tags: | ||
- AWS | ||
- GitHub Actions | ||
- Identity & Access Management | ||
Severity: High | ||
Description: > | ||
This policy ensures that IAM roles used with GitHub Actions are securely configured to prevent unauthorized access to AWS resources. | ||
It validates trust relationships by checking for proper audience (aud) restrictions, ensuring it is set to sts.amazonaws.com, and subject (sub) conditions, | ||
confirming they are scoped to specific repositories or environments. Misconfigurations, such as overly permissive wildcards or missing conditions, | ||
can allow unauthorized repositories to assume roles, leading to potential data breaches or compliance violations. | ||
By enforcing these checks, the policy mitigates risks of exploitation, enhances security posture, and protects critical AWS resources from external threats. | ||
Runbook: > | ||
To fix roles flagged by this policy: | ||
1. Update the trust relationship of the flagged IAM role in the AWS Management Console or CLI. | ||
2. Add a Condition block with 'StringLike' or 'StringEquals' for 'token.actions.githubusercontent.com:sub'. | ||
3. Ensure the audience is set to 'sts.amazonaws.com'. | ||
4. Avoid overly permissive wildcards in the sub condition. | ||
Reference: > | ||
- https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_create_for-idp_oidc.html | ||
- https://docs.github.com/en/actions/deployment/security-hardening-your-deployments/configuring-openid-connect-in-cloud-providers | ||
- https://docs.github.com/en/actions/security-for-github-actions/security-hardening-your-deployments/configuring-openid-connect-in-amazon-web-services | ||
Tests: | ||
- Name: Valid GitHub Actions Trust Relationship | ||
ExpectedResult: true | ||
Resource: | ||
{ | ||
"AssumeRolePolicyDocument": { | ||
"Version": "2012-10-17", | ||
"Statement": [ | ||
{ | ||
"Effect": "Allow", | ||
"Action": "sts:AssumeRoleWithWebIdentity", | ||
"Principal": { | ||
"Federated": "arn:aws:iam::123456789012:oidc-provider/token.actions.githubusercontent.com" | ||
}, | ||
"Condition": { | ||
"StringEquals": { | ||
"token.actions.githubusercontent.com:aud": "sts.amazonaws.com" | ||
}, | ||
"StringLike": { | ||
"token.actions.githubusercontent.com:sub": "repo:org/repo:*" | ||
} | ||
} | ||
} | ||
] | ||
} | ||
} | ||
|
||
- Name: Missing Audience Condition | ||
ExpectedResult: false | ||
Resource: | ||
{ | ||
"AssumeRolePolicyDocument": { | ||
"Version": "2012-10-17", | ||
"Statement": [ | ||
{ | ||
"Effect": "Allow", | ||
"Action": "sts:AssumeRoleWithWebIdentity", | ||
"Principal": { | ||
"Federated": "arn:aws:iam::123456789012:oidc-provider/token.actions.githubusercontent.com" | ||
}, | ||
"Condition": { | ||
"StringLike": { | ||
"token.actions.githubusercontent.com:sub": "repo:org/repo:*" | ||
} | ||
} | ||
} | ||
] | ||
} | ||
} | ||
|
||
- Name: Missing Subject Restriction | ||
ExpectedResult: false | ||
Resource: | ||
{ | ||
"AssumeRolePolicyDocument": { | ||
"Version": "2012-10-17", | ||
"Statement": [ | ||
{ | ||
"Effect": "Allow", | ||
"Action": "sts:AssumeRoleWithWebIdentity", | ||
"Principal": { | ||
"Federated": "arn:aws:iam::123456789012:oidc-provider/token.actions.githubusercontent.com" | ||
}, | ||
"Condition": { | ||
"StringEquals": { | ||
"token.actions.githubusercontent.com:aud": "sts.amazonaws.com" | ||
} | ||
} | ||
} | ||
] | ||
} | ||
} | ||
|
||
- Name: Overly Permissive Wildcard in Subject | ||
ExpectedResult: false | ||
Resource: | ||
{ | ||
"AssumeRolePolicyDocument": { | ||
"Version": "2012-10-17", | ||
"Statement": [ | ||
{ | ||
"Effect": "Allow", | ||
"Action": "sts:AssumeRoleWithWebIdentity", | ||
"Principal": { | ||
"Federated": "arn:aws:iam::123456789012:oidc-provider/token.actions.githubusercontent.com" | ||
}, | ||
"Condition": { | ||
"StringEquals": { | ||
"token.actions.githubusercontent.com:aud": "sts.amazonaws.com" | ||
}, | ||
"StringLike": { | ||
"token.actions.githubusercontent.com:sub": "*" | ||
} | ||
} | ||
} | ||
] | ||
} | ||
} | ||
|
||
- Name: Valid Subject Restriction with Specific Environment | ||
ExpectedResult: true | ||
Resource: | ||
{ | ||
"AssumeRolePolicyDocument": { | ||
"Version": "2012-10-17", | ||
"Statement": [ | ||
{ | ||
"Effect": "Allow", | ||
"Action": "sts:AssumeRoleWithWebIdentity", | ||
"Principal": { | ||
"Federated": "arn:aws:iam::123456789012:oidc-provider/token.actions.githubusercontent.com" | ||
}, | ||
"Condition": { | ||
"StringEquals": { | ||
"token.actions.githubusercontent.com:aud": "sts.amazonaws.com", | ||
"token.actions.githubusercontent.com:sub": "repo:org/repo:environment:prod" | ||
} | ||
} | ||
} | ||
] | ||
} | ||
} | ||
|
||
- Name: Invalid Principal as Wildcard | ||
ExpectedResult: false | ||
Resource: | ||
{ | ||
"AssumeRolePolicyDocument": { | ||
"Version": "2012-10-17", | ||
"Statement": [ | ||
{ | ||
"Effect": "Allow", | ||
"Action": "sts:AssumeRoleWithWebIdentity", | ||
"Principal": { | ||
"Federated": "*" | ||
}, | ||
"Condition": { | ||
"StringEquals": { | ||
"token.actions.githubusercontent.com:aud": "sts.amazonaws.com" | ||
}, | ||
"StringLike": { | ||
"token.actions.githubusercontent.com:sub": "repo:org/repo:*" | ||
} | ||
} | ||
} | ||
] | ||
} | ||
} | ||
|
||
- Name: Non-GitHub OIDC Principal | ||
ExpectedResult: false | ||
Resource: | ||
{ | ||
"AssumeRolePolicyDocument": { | ||
"Version": "2012-10-17", | ||
"Statement": [ | ||
{ | ||
"Effect": "Allow", | ||
"Action": "sts:AssumeRoleWithWebIdentity", | ||
"Principal": { | ||
"Federated": "arn:aws:iam::123456789012:oidc-provider/accounts.google.com" | ||
}, | ||
"Condition": { | ||
"StringEquals": { | ||
"token.actions.githubusercontent.com:aud": "sts.amazonaws.com" | ||
}, | ||
"StringLike": { | ||
"token.actions.githubusercontent.com:sub": "repo:org/repo:*" | ||
} | ||
} | ||
} | ||
] | ||
} | ||
} |