iam_cloudformation.yaml•19.5 kB
AWSTemplateFormatVersion: "2010-09-09"
Description: IAM roles needed to orchestrate the tests in the Github Actions
Parameters:
Repository:
Type: String
Description: "Fully qualified repository name, formatted as <organization>/<repository-name>"
Branches:
Type: String
Description: "The restrictions on which branches have permission to reach out to the OIDC provider. This is useful for security hardening of your github actions as described in https://docs.github.com/en/actions/security-guides/security-hardening-for-github-actions"
Regions:
Type: CommaDelimitedList
Default: "us-east-1,us-east-2,us-west-2,eu-west-1"
PrometheusWorkspaceID:
Type: String
Description: "Prometheus workspace to forward cluster prometheus metrics to"
DatabaseName:
Type: String
Description: "Timestream database to forward test metrics to"
TableName:
Type: String
Description: "Timestream table to forward test metrics to"
SweeperTableName:
Type: String
Description: "Timestream table to forward leaked resources to"
ResourceCountTableName:
Type: String
Description: "Timestream table to count number of resources to"
Resources:
GithubActionsPolicy:
Type: AWS::IAM::ManagedPolicy
Properties:
ManagedPolicyName: GithubActionsPolicy
PolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Action:
- cloudformation:CreateChangeSet
- cloudformation:CreateStack
- cloudformation:DeleteStack
- cloudformation:DescribeChangeSet
- cloudformation:DescribeStackEvents
- cloudformation:DescribeStackResources
- cloudformation:ExecuteChangeSet
- cloudformation:GetTemplate
- cloudformation:GetTemplateSummary
Resource:
- !Sub "arn:${AWS::Partition}:cloudformation:*:${AWS::AccountId}:stack/iam-*"
- !Sub "arn:${AWS::Partition}:cloudformation:*:${AWS::AccountId}:stack/eksctl-*"
Condition:
StringEquals:
aws:RequestedRegion:
Ref: Regions
- Effect: Allow
Action:
- cloudformation:ListStacks
- cloudformation:DescribeStacks
Resource: "*"
- Effect: Allow
Action: logs:PutRetentionPolicy
Resource: !Sub "arn:aws:logs:*:${AWS::AccountId}:log-group:/aws/eks/*"
- Effect: Allow
Action: fis:CreateExperimentTemplate
Resource: !Sub "arn:${AWS::Partition}:fis:*:${AWS::AccountId}:action/*"
Condition:
StringEquals:
aws:RequestedRegion:
Ref: Regions
- Effect: Allow
Action:
- fis:CreateExperimentTemplate
- fis:DeleteExperimentTemplate
- fis:StartExperiment
Resource:
- !Sub "arn:${AWS::Partition}:fis:*:${AWS::AccountId}:experiment-template/*"
Condition:
StringEquals:
aws:RequestedRegion:
Ref: Regions
- Effect: Allow
Action:
- fis:GetExperiment
- fis:StartExperiment
Resource:
- !Sub "arn:${AWS::Partition}:fis:*:${AWS::AccountId}:experiment/*"
Condition:
StringEquals:
aws:RequestedRegion:
Ref: Regions
- Effect: Allow
Action:
- iam:CreateServiceLinkedRole
Resource:
- !Sub "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/aws-service-role/eks-nodegroup.amazonaws.com/AWSServiceRoleForAmazonEKSNodegroup"
- !Sub "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/aws-service-role/spot.amazonaws.com/AWSServiceRoleForEC2Spot"
- !Sub "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/aws-service-role/elasticloadbalancing.amazonaws.com/AWSServiceRoleForElasticLoadBalancing"
- Effect: Allow
Action:
- sqs:CreateQueue
- sqs:AddPermission
- sqs:TagQueue
- sqs:SetQueueAttributes
- sqs:GetQueueAttributes
- sqs:GetQueueUrl
- sqs:RemovePermission
- sqs:DeleteQueue
- sqs:UntagQueue
Resource:
- !Sub "arn:${AWS::Partition}:sqs:*:${AWS::AccountId}:*"
Condition:
StringEquals:
aws:RequestedRegion:
Ref: Regions
- Effect: Allow
Action:
- events:PutRule
- events:DeleteRule
- events:DescribeRule
- events:PutTargets
- events:RemoveTargets
- events:EnableRule
Resource: !Sub "arn:${AWS::Partition}:events:*:${AWS::AccountId}:rule/*"
Condition:
StringEquals:
aws:RequestedRegion:
Ref: Regions
- Effect: Allow
Action: timestream:WriteRecords
Resource:
- !Sub "arn:${AWS::Partition}:timestream:${AWS::Region}:${AWS::AccountId}:database/${DatabaseName}/table/${TableName}"
- !Sub "arn:${AWS::Partition}:timestream:${AWS::Region}:${AWS::AccountId}:database/${DatabaseName}/table/${SweeperTableName}"
- !Sub "arn:${AWS::Partition}:timestream:${AWS::Region}:${AWS::AccountId}:database/${DatabaseName}/table/${ResourceCountTableName}"
- Effect: Allow
Action: timestream:DescribeEndpoints
Resource: "*"
GithubActionsIAMPolicy:
Type: AWS::IAM::ManagedPolicy
Properties:
ManagedPolicyName: GithubActionsIAMPolicy
PolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Action:
- iam:AttachRolePolicy
- iam:CreateRole
- iam:TagRole
- iam:DeleteRolePolicy
- iam:DetachRolePolicy
- iam:PutRolePolicy
Resource:
- !Sub "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/KarpenterNodeRole-*"
- !Sub "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/eksctl-*"
- !Sub "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/karpenter-irsa-*"
- !Sub "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/prometheus-irsa-*"
Condition:
ArnEquals:
"iam:PermissionsBoundary": !Ref GithubActionsPermissionsBoundary
- Effect: Allow
Action: iam:DeleteRole
Resource:
- !Sub "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/KarpenterNodeRole-*"
- !Sub "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/eksctl-*"
- !Sub "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/karpenter-irsa-*"
- !Sub "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/prometheus-irsa-*"
- Effect: Allow
Action:
- iam:GetRole
- iam:GetRolePolicy
- iam:ListAttachedRolePolicies
Resource:
- !Sub "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/aws-service-role/eks-nodegroup.amazonaws.com/AWSServiceRoleForAmazonEKSNodegroup"
- !Sub "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/KarpenterNodeRole-*"
- !Sub "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/eksctl-*"
- !Sub "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/karpenter-irsa-*"
- !Sub "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/prometheus-irsa-*"
- !GetAtt FISInterruptionRole.Arn
- Effect: Allow
Action: iam:PassRole
Resource: !Sub "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/eksctl-*"
- Effect: Allow
Action:
- iam:ListInstanceProfiles
- iam:ListInstanceProfileTags
Resource:
- !Sub "arn:${AWS::Partition}:iam::${AWS::AccountId}:instance-profile/*"
- Effect: Allow
Action:
- iam:AddRoleToInstanceProfile
- iam:CreateInstanceProfile
- iam:TagInstanceProfile
- iam:RemoveRoleFromInstanceProfile
- iam:DeleteInstanceProfile
- iam:GetInstanceProfile
Resource:
- !Sub "arn:${AWS::Partition}:iam::${AWS::AccountId}:instance-profile/KarpenterNodeInstanceProfile-*"
- !Sub "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/KarpenterNodeRole-*"
- !Sub "arn:${AWS::Partition}:iam::${AWS::AccountId}:instance-profile/KarpenterNodeInstanceProfile-Drift-*"
- Effect: Allow
Action:
- iam:CreateOpenIDConnectProvider
- iam:DeleteOpenIDConnectProvider
- iam:ListOpenIDConnectProviders
- iam:ListOpenIDConnectProviderTags
- iam:TagOpenIDConnectProvider
- iam:GetOpenIDConnectProvider
- iam:TagOpenIDConnectProvider
Resource: !Sub "arn:${AWS::Partition}:iam::${AWS::AccountId}:oidc-provider/*"
- Effect: Allow
Action:
- iam:CreatePolicy
- iam:DeletePolicy
- iam:GetPolicy
- iam:CreatePolicyVersion
- iam:DeletePolicyVersion
- iam:ListPolicyVersions
Resource: !Sub "arn:${AWS::Partition}:iam::${AWS::AccountId}:policy/KarpenterControllerPolicy-*"
GithubActionsEKSPolicy:
Type: AWS::IAM::ManagedPolicy
Properties:
ManagedPolicyName: GithubActionsEKSPolicy
PolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Action:
- eks:CreateCluster
- eks:CreateAddon
- eks:CreateNodegroup
- eks:CreatePodIdentityAssociation
- eks:DeleteCluster
- eks:ListFargateProfiles
- eks:TagResource
- eks:DescribeCluster
- eks:ListClusters
- eks:CreateAccessEntry
Resource: !Sub "arn:${AWS::Partition}:eks:*:${AWS::AccountId}:cluster/*"
Condition:
StringEquals:
aws:RequestedRegion:
Ref: Regions
- Effect: Allow
Action:
- eks:DeleteAccessEntry
Resource:
- !Sub "arn:${AWS::Partition}:eks:*:${AWS::AccountId}:access-entry/*/role/${AWS::AccountId}/KarpenterNodeRole-*"
Condition:
StringEquals:
aws:RequestedRegion:
Ref: Regions
- Effect: Allow
Action:
- eks:DeleteAddon
- eks:DescribeAddon
Resource:
- !Sub "arn:${AWS::Partition}:eks:*:${AWS::AccountId}:addon/*"
Condition:
StringEquals:
aws:RequestedRegion:
Ref: Regions
- Effect: Allow
Action:
- eks:DeleteNodegroup
- eks:DescribeNodegroup
- eks:TagResource
Resource: !Sub "arn:${AWS::Partition}:eks:*:${AWS::AccountId}:nodegroup/*"
Condition:
StringEquals:
aws:RequestedRegion:
Ref: Regions
- Effect: Allow
Action:
- eks:TagResource
Resource: !Sub "arn:${AWS::Partition}:eks:*:${AWS::AccountId}:podidentityassociation/*"
Condition:
StringEquals:
aws:RequestedRegion:
Ref: Regions
# GithubActionsPermissionsBoundary includes all permissions needed for all designated roles provisioned by the GithubActions
# CI task. This includes the cluster ServiceRoles that are generated by EKSCTL and all roles generated with IRSA to interface from the
# cluster into AWS services through IAM.
# The policies that are captured inside the GithubActionsPermissionsBoundary include:
# - AmazonEC2ContainerRegistryPullOnly
# - AmazonEKSWorkerNodePolicy
# - AmazonSSMManagedInstanceCore
# - AmazonEBSCSIDriverPolicy
# - EBS CSI Driver Controller Policy (used by IRSA)
# - Prometheus Controller Policy (used by IRSA)
# - Karpenter Controller Policy (used by IRSA)
# - VPC CNI Daemonset Policy (used by IRSA)
GithubActionsPermissionsBoundary:
Type: AWS::IAM::ManagedPolicy
Properties:
ManagedPolicyName: GithubActionsPermissionsBoundary
PolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Action:
- ec2:*
# Permissions to pull ECR images needed by the NodeInstanceRole
- ecr:GetAuthorizationToken
- ecr:BatchGetImage
- ecr:GetDownloadUrlForLayer
- ecr:BatchImportUpstreamImage
# EKS ServiceRole permissions needed for AutoScalingGroups
- autoscaling:DescribeAutoScalingGroups
- autoscaling:UpdateAutoScalingGroup
# EKS ServiceRole permissions needed to handle LoadBalancer
- elasticloadbalancing:*
- kms:CreateGrant
- kms:GenerateDataKeyWithoutPlaintext
- kms:DescribeKey
# SSM Permissions for AmazonSSMManagedInstanceCore policy applied to the NodeInstanceRole
- ssm:*
# SSM Permissions for AmazonSSMManagedInstanceCore policy applied to the NodeInstanceRole
- ssmmessages:*
# SSM Permissions for AmazonSSMManagedInstanceCore policy applied to the NodeInstanceRole
- ec2messages:*
- sqs:DeleteMessage
- sqs:GetQueueAttributes
- sqs:GetQueueUrl
- sqs:SendMessage
- sqs:ReceiveMessage
- pricing:GetProducts
- eks:DescribeCluster
- eks-auth:AssumeRoleForPodIdentity
Resource: "*"
- Effect: Allow
Action: iam:PassRole
Resource:
- !Sub "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/karpenter-irsa-*"
- !Sub "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/prometheus-irsa-*"
- !Sub "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/KarpenterNodeRole-*"
- !GetAtt FISInterruptionRole.Arn
- Effect: Allow
Action: iam:CreateInstanceProfile
Resource: "*"
Condition:
StringLike:
aws:RequestTag/karpenter.k8s.aws/ec2nodeclass: "*"
- Effect: Allow
Action: iam:TagInstanceProfile
Resource: "*"
Condition:
StringLike:
aws:RequestTag/karpenter.k8s.aws/ec2nodeclass: "*"
aws:ResourceTag/karpenter.k8s.aws/ec2nodeclass: "*"
- Effect: Allow
Action:
- iam:AddRoleToInstanceProfile
- iam:RemoveRoleFromInstanceProfile
- iam:DeleteInstanceProfile
Resource: "*"
Condition:
StringLike:
aws:ResourceTag/karpenter.k8s.aws/ec2nodeclass: "*"
- Effect: Allow
Action:
- iam:GetInstanceProfile
- iam:ListInstanceProfiles
Resource: "*"
- Effect: Allow
Action:
- aps:RemoteWrite
- aps:GetSeries
- aps:GetLabels
- aps:GetMetricMetadata
Resource: !Sub "arn:${AWS::Partition}:aps:${AWS::Region}:${AWS::AccountId}:workspace/${PrometheusWorkspaceID}"
# Deny ALL IMDSv1 instance launch
- Effect: Deny
Action:
- ec2:RunInstances
Resource: !Sub "arn:${AWS::Partition}:ec2:*:${AWS::AccountId}:instance/*"
Condition:
StringNotEquals:
ec2:MetadataHttpTokens: required
- Effect: Deny
Action:
- ec2:ModifyInstanceMetadataOptions
Resource: !Sub "arn:${AWS::Partition}:ec2:*:${AWS::AccountId}:instance/*"
Condition:
StringEquals:
ec2:Attribute: HttpTokens
StringNotEquals:
ec2:Attribute/HttpTokens: required
- Effect: Allow
Action:
- iam:CreateRole
- iam:DeleteRole
Resource:
- !Sub "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/KarpenterNodeRole-*"
- Effect: Allow
Action:
- iam:AttachRolePolicy
- iam:DetachRolePolicy
Resource:
- !Sub "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/KarpenterNodeRole-*"
Condition:
ArnEquals:
"iam:PolicyARN":
- "arn:aws:iam::aws:policy/AmazonEKS_CNI_Policy"
- "arn:aws:iam::aws:policy/AmazonEKSWorkerNodePolicy"
- "arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryPullOnly"
- "arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore"
- Effect: Allow
Action:
- iam:GetRole
Resource:
- !Sub "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/*"
GithubActionsRole:
Type: AWS::IAM::Role
Properties:
RoleName: GithubActionsRole
ManagedPolicyArns:
- !Ref GithubActionsPolicy
- !Ref GithubActionsEKSPolicy
- !Ref GithubActionsIAMPolicy
- !Ref GithubActionsPermissionsBoundary
MaxSessionDuration: 21600 # 6 hours is the max session for GHA
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Principal:
Federated: !Sub "arn:aws:iam::${AWS::AccountId}: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: !Sub "repo:${Repository}:ref:${Branches}"
- Effect: Allow
Principal:
AWS: !Sub "arn:aws:iam::${AWS::AccountId}:root"
Action: "sts:AssumeRole"
FISInterruptionRole:
Type: AWS::IAM::Role
Properties:
RoleName: FISInterruptionRole
ManagedPolicyArns:
- !Ref FISInterruptionPolicy
MaxSessionDuration: 3600
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Principal:
Service: "fis.amazonaws.com"
Action: "sts:AssumeRole"
FISInterruptionPolicy:
Type: AWS::IAM::ManagedPolicy
Properties:
ManagedPolicyName: FISInterruptionPolicy
PolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Action: ec2:SendSpotInstanceInterruptions
Resource:
- !Sub "arn:${AWS::Partition}:ec2:*:${AWS::AccountId}:instance/*"
Condition:
StringEquals:
aws:RequestedRegion:
Ref: Regions