Skip to content

Instantly share code, notes, and snippets.

@badideasforsale
Last active July 18, 2025 05:21
Show Gist options
  • Save badideasforsale/ad0219f5409bb66d3d5b71a3d5ee016a to your computer and use it in GitHub Desktop.
Save badideasforsale/ad0219f5409bb66d3d5b71a3d5ee016a to your computer and use it in GitHub Desktop.
Create OIDC connection for GitHub Actions to use in AWS
#!/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