Last active
July 18, 2025 05:21
-
-
Save badideasforsale/ad0219f5409bb66d3d5b71a3d5ee016a to your computer and use it in GitHub Desktop.
Create OIDC connection for GitHub Actions to use in AWS
This file contains hidden or 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
#!/bin/bash | |
# Script to create OIDC provider for GitHub Actions | |
# This script creates an OIDC provider in AWS for GitHub Actions to assume roles | |
# It also creates an IAM role with the appropriate trust policy for the specified repository | |
set -euo pipefail # Exit on error, undefined variables, and pipe failures | |
# Color codes for output formatting | |
readonly RED='\033[0;31m' | |
readonly GREEN='\033[0;32m' | |
readonly YELLOW='\033[1;33m' | |
readonly BLUE='\033[0;34m' | |
readonly NC='\033[0m' # No Color | |
# Global variables | |
ROLE_NAME="" | |
GIT_ORG="" | |
GIT_REPO="" | |
ARPD_FILE="" | |
# Function to print colored output | |
log_info() { | |
echo -e "${BLUE}[INFO]${NC} $1" | |
} | |
log_success() { | |
echo -e "${GREEN}[SUCCESS]${NC} $1" | |
} | |
log_warning() { | |
echo -e "${YELLOW}[WARNING]${NC} $1" | |
} | |
log_error() { | |
echo -e "${RED}[ERROR]${NC} $1" >&2 | |
} | |
# Function to display comprehensive help text | |
show_help() { | |
echo -e "${BLUE}GitHub Actions OIDC Provider Setup Script${NC}" | |
echo | |
echo -e "${YELLOW}DESCRIPTION:${NC}" | |
echo " This script creates an OpenID Connect (OIDC) provider in AWS for GitHub Actions" | |
echo " and sets up an IAM role that can be assumed by GitHub Actions workflows from" | |
echo " the specified repository." | |
echo | |
echo -e "${YELLOW}PREREQUISITES:${NC}" | |
echo " - AWS CLI installed and configured with appropriate permissions" | |
echo " - IAM permissions to create OIDC providers and roles" | |
echo " - Valid GitHub organization/user and repository names" | |
echo | |
echo -e "${YELLOW}USAGE:${NC}" | |
echo " $0 -r <role_name> -o <git_org> -g <git_repo> [options]" | |
echo | |
echo -e "${YELLOW}REQUIRED OPTIONS:${NC}" | |
echo " -r <role_name> Name of the IAM role to create" | |
echo " -o <git_org> GitHub organization or username (no wildcards)" | |
echo " -g <git_repo> GitHub repository name (no wildcards)" | |
echo | |
echo -e "${YELLOW}OTHER OPTIONS:${NC}" | |
echo " -h Show this help message and exit" | |
echo | |
echo -e "${YELLOW}EXAMPLES:${NC}" | |
echo " # Create OIDC setup for a specific repository" | |
echo " $0 -r MyGitHubActionsRole -o myorg -g myrepo" | |
echo | |
echo " # Create OIDC setup for a user's repository" | |
echo " $0 -r DeploymentRole -o myusername -g my-project" | |
echo | |
echo -e "${YELLOW}NOTES:${NC}" | |
echo " - The script will create an OIDC provider if it doesn't already exist" | |
echo " - The IAM role will only trust the specific repository provided" | |
echo " - You'll need to attach appropriate policies to the created role separately" | |
echo " - The trust policy allows any branch/environment within the specified repo" | |
echo | |
echo -e "${YELLOW}SECURITY CONSIDERATIONS:${NC}" | |
echo " - The created role can be assumed by any workflow in the specified repository" | |
echo " - Consider restricting the trust policy further for production use" | |
echo " - Always follow the principle of least privilege when attaching policies" | |
echo | |
} | |
# Function to validate input parameters | |
validate_inputs() { | |
log_info "Validating input parameters..." | |
# Check for wildcards in org name | |
if [[ "$GIT_ORG" == *"*"* ]]; then | |
log_error "Git organization cannot contain wildcards (*)" | |
exit 1 | |
fi | |
# Check for wildcards in repo name | |
if [[ "$GIT_REPO" == *"*"* ]]; then | |
log_error "Git repository cannot contain wildcards (*)" | |
exit 1 | |
fi | |
# Validate org name format (basic GitHub username/org validation) | |
if [[ ! "$GIT_ORG" =~ ^[a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?$ ]]; then | |
log_error "Invalid GitHub organization/username format: $GIT_ORG" | |
log_error "Must start and end with alphanumeric characters, can contain hyphens" | |
exit 1 | |
fi | |
# Validate repo name format | |
if [[ ! "$GIT_REPO" =~ ^[a-zA-Z0-9._-]+$ ]]; then | |
log_error "Invalid GitHub repository name format: $GIT_REPO" | |
log_error "Can only contain alphanumeric characters, dots, hyphens, and underscores" | |
exit 1 | |
fi | |
# Validate role name format | |
if [[ ! "$ROLE_NAME" =~ ^[a-zA-Z0-9+=,.@_-]+$ ]]; then | |
log_error "Invalid IAM role name format: $ROLE_NAME" | |
log_error "Can only contain alphanumeric characters and +=,.@_-" | |
exit 1 | |
fi | |
log_success "Input validation passed" | |
} | |
# Function to check prerequisites | |
check_prerequisites() { | |
log_info "Checking prerequisites..." | |
# Check if AWS CLI is installed | |
if ! command -v aws &> /dev/null; then | |
log_error "AWS CLI is not installed or not in PATH" | |
log_error "Please install AWS CLI: https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html" | |
exit 1 | |
fi | |
# Check AWS credentials and get account ID | |
log_info "Verifying AWS credentials..." | |
if ! AWS_ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text 2>/dev/null); then | |
log_error "Failed to get AWS account ID" | |
log_error "Please ensure AWS credentials are configured correctly" | |
log_error "Run 'aws configure' or set AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY" | |
exit 1 | |
fi | |
if [[ -z "$AWS_ACCOUNT_ID" ]]; then | |
log_error "AWS account ID is empty - credential issue detected" | |
exit 1 | |
fi | |
log_success "Prerequisites check passed - AWS Account ID: $AWS_ACCOUNT_ID" | |
} | |
# Function to create OIDC provider (if it doesn't exist) | |
create_oidc_provider() { | |
local oidc_provider_arn="arn:aws:iam::${AWS_ACCOUNT_ID}:oidc-provider/token.actions.githubusercontent.com" | |
log_info "Checking if OIDC provider already exists..." | |
# Check if OIDC provider already exists | |
if aws iam get-open-id-connect-provider --open-id-connect-provider-arn "$oidc_provider_arn" &>/dev/null; then | |
log_warning "OIDC provider already exists, skipping creation" | |
return 0 | |
fi | |
log_info "Creating OpenID Connect provider for GitHub Actions..." | |
# Create OIDC provider | |
# The thumbprint is required for CLI creation but ignored by AWS for GitHub Actions | |
if aws iam create-open-id-connect-provider \ | |
--url https://token.actions.githubusercontent.com \ | |
--thumbprint-list 1b511abead59c6ce207077c0bf0e0043b1382612 \ | |
--client-id-list sts.amazonaws.com \ | |
--output text &>/dev/null; then | |
log_success "OIDC provider created successfully" | |
else | |
log_error "Failed to create OIDC provider" | |
exit 1 | |
fi | |
} | |
# Function to create trust policy document | |
create_trust_policy() { | |
log_info "Creating trust policy document..." | |
ARPD_FILE=$(mktemp) | |
cat << EOF > "${ARPD_FILE}" | |
{ | |
"Version": "2012-10-17", | |
"Statement": [ | |
{ | |
"Effect": "Allow", | |
"Principal": { | |
"Federated": "arn:aws:iam::${AWS_ACCOUNT_ID}: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:${GIT_ORG}/${GIT_REPO}:*" | |
} | |
} | |
} | |
] | |
} | |
EOF | |
log_success "Trust policy document created" | |
} | |
# Function to create IAM role | |
create_iam_role() { | |
log_info "Checking if IAM role already exists..." | |
# Check if role already exists | |
if aws iam get-role --role-name "$ROLE_NAME" &>/dev/null; then | |
log_error "IAM role '$ROLE_NAME' already exists" | |
log_error "Please choose a different role name or delete the existing role first" | |
exit 1 | |
fi | |
log_info "Creating IAM role '$ROLE_NAME'..." | |
if aws iam create-role \ | |
--role-name "$ROLE_NAME" \ | |
--assume-role-policy-document "file://${ARPD_FILE}" \ | |
--description "GitHub Actions OIDC role for ${GIT_ORG}/${GIT_REPO}" \ | |
--output text &>/dev/null; then | |
log_success "IAM role '$ROLE_NAME' created successfully" | |
else | |
log_error "Failed to create IAM role '$ROLE_NAME'" | |
exit 1 | |
fi | |
} | |
# Function to clean up temporary files | |
cleanup() { | |
if [[ -n "$ARPD_FILE" && -f "$ARPD_FILE" ]]; then | |
rm -f "$ARPD_FILE" | |
log_info "Cleaned up temporary files" | |
fi | |
} | |
# Function to display final instructions | |
show_final_instructions() { | |
echo | |
echo -e "${GREEN}🎉 Setup completed successfully!${NC}" | |
echo | |
echo -e "${YELLOW}NEXT STEPS:${NC}" | |
echo "1. Attach appropriate policies to the role '${ROLE_NAME}' based on your needs" | |
echo "2. Use the following in your GitHub Actions workflow:" | |
echo | |
echo -e "${BLUE}Example workflow step:${NC}" | |
echo " - name: Configure AWS credentials" | |
echo " uses: aws-actions/configure-aws-credentials@v4" | |
echo " with:" | |
echo " role-to-assume: arn:aws:iam::${AWS_ACCOUNT_ID}:role/${ROLE_NAME}" | |
echo " aws-region: us-east-1 # Change to your preferred region" | |
echo | |
echo -e "${YELLOW}SECURITY REMINDER:${NC}" | |
echo "- The role can be assumed by any workflow in the ${GIT_ORG}/${GIT_REPO} repository" | |
echo "- Consider adding more restrictive conditions if needed" | |
echo "- Always follow the principle of least privilege when attaching policies" | |
echo | |
} | |
# Main execution function | |
main() { | |
# Set up cleanup trap | |
trap cleanup EXIT | |
# Parse command line arguments | |
while getopts ":r:o:g:h" opt; do | |
case $opt in | |
r) ROLE_NAME="$OPTARG" ;; | |
o) GIT_ORG="$OPTARG" ;; | |
g) GIT_REPO="$OPTARG" ;; | |
h) show_help; exit 0 ;; | |
:) log_error "Option -$OPTARG requires an argument"; exit 1 ;; | |
\?) log_error "Invalid option: -$OPTARG"; show_help; exit 1 ;; | |
esac | |
done | |
# Check if required options are provided | |
if [[ -z "$ROLE_NAME" ]]; then | |
log_error "Must supply a role name with -r" | |
show_help | |
exit 1 | |
fi | |
if [[ -z "$GIT_ORG" ]]; then | |
log_error "Must supply a git organization or user with -o" | |
show_help | |
exit 1 | |
fi | |
if [[ -z "$GIT_REPO" ]]; then | |
log_error "Must supply a git repository with -g" | |
show_help | |
exit 1 | |
fi | |
# Execute main workflow | |
validate_inputs | |
check_prerequisites | |
create_oidc_provider | |
create_trust_policy | |
create_iam_role | |
show_final_instructions | |
log_success "All operations completed successfully!" | |
} | |
# Run main function | |
main "$@" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment