Amazon EKS + Fargate プロファイルによるサーバーレス Kubernetes 環境を構築します。AWS Load Balancer Controller 用の IRSA(IAM Roles for Service Accounts)設定と ECR リポジトリを含み、ALB Ingress による外部公開に対応します。
AWS CLIを使用してCloudFormationスタックをデプロイする場合は、以下のコマンドを実行します。
aws cloudformation deploy \ --template-file eks-cluster.yaml \ --stack-name eks-cluster-stack \ --capabilities CAPABILITY_IAM CAPABILITY_NAMED_IAM
AWSTemplateFormatVersion: '2010-09-09'
Description: 'Amazon EKS Cluster with Fargate, ALB Ingress Controller (AWS Load Balancer Controller), and ECR'
Parameters:
Environment:
Type: String
Default: dev
AllowedValues: [dev, prod]
KubernetesVersion:
Type: String
Default: '1.32'
Description: EKS Kubernetes version
Resources:
# VPC
VPC:
Type: AWS::EC2::VPC
Properties:
CidrBlock: 10.0.0.0/16
EnableDnsHostnames: true
EnableDnsSupport: true
Tags:
- Key: Name
Value: !Sub 'eks-vpc-${Environment}'
PublicSubnetOne:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref VPC
CidrBlock: 10.0.0.0/24
AvailabilityZone: !Select [0, !GetAZs '']
MapPublicIpOnLaunch: true
Tags:
- Key: Name
Value: !Sub 'eks-public-1-${Environment}'
- Key: kubernetes.io/role/elb
Value: '1'
PublicSubnetTwo:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref VPC
CidrBlock: 10.0.1.0/24
AvailabilityZone: !Select [1, !GetAZs '']
MapPublicIpOnLaunch: true
Tags:
- Key: Name
Value: !Sub 'eks-public-2-${Environment}'
- Key: kubernetes.io/role/elb
Value: '1'
PrivateSubnetOne:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref VPC
CidrBlock: 10.0.2.0/24
AvailabilityZone: !Select [0, !GetAZs '']
Tags:
- Key: Name
Value: !Sub 'eks-private-1-${Environment}'
- Key: kubernetes.io/role/internal-elb
Value: '1'
PrivateSubnetTwo:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref VPC
CidrBlock: 10.0.3.0/24
AvailabilityZone: !Select [1, !GetAZs '']
Tags:
- Key: Name
Value: !Sub 'eks-private-2-${Environment}'
- Key: kubernetes.io/role/internal-elb
Value: '1'
InternetGateway:
Type: AWS::EC2::InternetGateway
GatewayAttachment:
Type: AWS::EC2::VPCGatewayAttachment
Properties:
VpcId: !Ref VPC
InternetGatewayId: !Ref InternetGateway
NatGatewayEIP:
Type: AWS::EC2::EIP
DependsOn: GatewayAttachment
Properties:
Domain: vpc
NatGateway:
Type: AWS::EC2::NatGateway
Properties:
AllocationId: !GetAtt NatGatewayEIP.AllocationId
SubnetId: !Ref PublicSubnetOne
PublicRouteTable:
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref VPC
PublicRoute:
Type: AWS::EC2::Route
DependsOn: GatewayAttachment
Properties:
RouteTableId: !Ref PublicRouteTable
DestinationCidrBlock: 0.0.0.0/0
GatewayId: !Ref InternetGateway
PublicSubnetOneAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
SubnetId: !Ref PublicSubnetOne
RouteTableId: !Ref PublicRouteTable
PublicSubnetTwoAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
SubnetId: !Ref PublicSubnetTwo
RouteTableId: !Ref PublicRouteTable
PrivateRouteTable:
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref VPC
PrivateRoute:
Type: AWS::EC2::Route
Properties:
RouteTableId: !Ref PrivateRouteTable
DestinationCidrBlock: 0.0.0.0/0
NatGatewayId: !Ref NatGateway
PrivateSubnetOneAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
SubnetId: !Ref PrivateSubnetOne
RouteTableId: !Ref PrivateRouteTable
PrivateSubnetTwoAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
SubnetId: !Ref PrivateSubnetTwo
RouteTableId: !Ref PrivateRouteTable
# Security Groups
ClusterSecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: EKS cluster security group
VpcId: !Ref VPC
Tags:
- Key: Name
Value: !Sub 'eks-cluster-sg-${Environment}'
# IAM Role for EKS Cluster
EKSClusterRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
Service: eks.amazonaws.com
Action: sts:AssumeRole
ManagedPolicyArns:
- arn:aws:iam::aws:policy/AmazonEKSClusterPolicy
# EKS Cluster
EKSCluster:
Type: AWS::EKS::Cluster
Properties:
Name: !Sub 'eks-cluster-${Environment}'
Version: !Ref KubernetesVersion
RoleArn: !GetAtt EKSClusterRole.Arn
ResourcesVpcConfig:
SubnetIds:
- !Ref PublicSubnetOne
- !Ref PublicSubnetTwo
- !Ref PrivateSubnetOne
- !Ref PrivateSubnetTwo
SecurityGroupIds:
- !Ref ClusterSecurityGroup
EndpointPublicAccess: true
EndpointPrivateAccess: true
Logging:
ClusterLogging:
EnabledTypes:
- Type: api
- Type: audit
- Type: authenticator
- Type: controllerManager
- Type: scheduler
Tags:
- Key: Environment
Value: !Ref Environment
# Fargate Profile for system pods
FargateProfileSystem:
Type: AWS::EKS::FargateProfile
Properties:
ClusterName: !Ref EKSCluster
FargateProfileName: !Sub 'fargate-system-${Environment}'
PodExecutionRoleArn: !GetAtt FargatePodExecutionRole.Arn
Subnets:
- !Ref PrivateSubnetOne
- !Ref PrivateSubnetTwo
Selectors:
- Namespace: kube-system
- Namespace: default
# Fargate Profile for application pods
FargateProfileApp:
Type: AWS::EKS::FargateProfile
Properties:
ClusterName: !Ref EKSCluster
FargateProfileName: !Sub 'fargate-app-${Environment}'
PodExecutionRoleArn: !GetAtt FargatePodExecutionRole.Arn
Subnets:
- !Ref PrivateSubnetOne
- !Ref PrivateSubnetTwo
Selectors:
- Namespace: app
Labels:
environment: !Ref Environment
# IAM Role for Fargate Pod Execution
FargatePodExecutionRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
Service: eks-fargate-pods.amazonaws.com
Action: sts:AssumeRole
ManagedPolicyArns:
- arn:aws:iam::aws:policy/AmazonEKSFargatePodExecutionRolePolicy
# ECR Repository
ECRRepository:
Type: AWS::ECR::Repository
Properties:
ImageScanningConfiguration:
ScanOnPush: true
EncryptionConfiguration:
EncryptionType: KMS
LifecyclePolicy:
LifecyclePolicyText: |
{
"rules": [{
"rulePriority": 1,
"description": "Keep last 10 images",
"selection": {
"tagStatus": "any",
"countType": "imageCountMoreThan",
"countNumber": 10
},
"action": { "type": "expire" }
}]
}
Tags:
- Key: Environment
Value: !Ref Environment
# OIDC Provider for IRSA (IAM Roles for Service Accounts)
# Note: OIDCProvider requires the cluster OIDC issuer URL.
# After cluster creation, retrieve it with:
# aws eks describe-cluster --name <cluster-name> --query "cluster.identity.oidc.issuer"
# Then create the OIDC provider via:
# eksctl utils associate-iam-oidc-provider --cluster <cluster-name> --approve
# IAM Role for AWS Load Balancer Controller (IRSA)
# The AWS Load Balancer Controller replaces the legacy ALB Ingress Controller.
# It is installed via Helm after cluster creation and uses IRSA for permissions.
AWSLoadBalancerControllerRole:
Type: AWS::IAM::Role
Properties:
RoleName: !Sub 'AmazonEKSLoadBalancerControllerRole-${Environment}'
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
Federated: !Sub 'arn:aws:iam::${AWS::AccountId}:oidc-provider/oidc.eks.${AWS::Region}.amazonaws.com/id/EXAMPLED539D4633E53DE1B71EXAMPLE'
Action: sts:AssumeRoleWithWebIdentity
Condition:
StringEquals:
'oidc.eks.${AWS::Region}.amazonaws.com/id/EXAMPLED539D4633E53DE1B71EXAMPLE:sub': 'system:serviceaccount:kube-system:aws-load-balancer-controller'
'oidc.eks.${AWS::Region}.amazonaws.com/id/EXAMPLED539D4633E53DE1B71EXAMPLE:aud': 'sts.amazonaws.com'
Policies:
- PolicyName: AWSLoadBalancerControllerPolicy
PolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Action:
- ec2:DescribeAccountAttributes
- ec2:DescribeAddresses
- ec2:DescribeAvailabilityZones
- ec2:DescribeInternetGateways
- ec2:DescribeVpcs
- ec2:DescribeSubnets
- ec2:DescribeSecurityGroups
- ec2:DescribeInstances
- ec2:DescribeNetworkInterfaces
- ec2:DescribeTags
- ec2:GetCoipPoolUsage
- ec2:DescribeCoipPools
- elasticloadbalancing:DescribeLoadBalancers
- elasticloadbalancing:DescribeLoadBalancerAttributes
- elasticloadbalancing:DescribeListeners
- elasticloadbalancing:DescribeListenerCertificates
- elasticloadbalancing:DescribeSSLPolicies
- elasticloadbalancing:DescribeRules
- elasticloadbalancing:DescribeTargetGroups
- elasticloadbalancing:DescribeTargetGroupAttributes
- elasticloadbalancing:DescribeTargetHealth
- elasticloadbalancing:DescribeTags
Resource: '*'
- Effect: Allow
Action:
- cognito-idp:DescribeUserPoolClient
- acm:ListCertificates
- acm:DescribeCertificate
- iam:ListServerCertificates
- iam:GetServerCertificate
- waf-regional:GetWebACL
- waf-regional:GetWebACLForResource
- waf-regional:AssociateWebACL
- waf-regional:DisassociateWebACL
- wafv2:GetWebACL
- wafv2:GetWebACLForResource
- wafv2:AssociateWebACL
- wafv2:DisassociateWebACL
- shield:GetSubscriptionState
- shield:DescribeProtection
- shield:CreateProtection
- shield:DeleteProtection
Resource: '*'
- Effect: Allow
Action:
- ec2:AuthorizeSecurityGroupIngress
- ec2:RevokeSecurityGroupIngress
- ec2:CreateSecurityGroup
- ec2:CreateTags
- ec2:DeleteTags
- ec2:DeleteSecurityGroup
- ec2:DescribeSecurityGroupRules
- ec2:ModifySecurityGroupRules
- ec2:RevokeSecurityGroupEgress
Resource: '*'
- Effect: Allow
Action:
- elasticloadbalancing:CreateLoadBalancer
- elasticloadbalancing:CreateTargetGroup
- elasticloadbalancing:CreateListener
- elasticloadbalancing:DeleteListener
- elasticloadbalancing:CreateRule
- elasticloadbalancing:DeleteRule
- elasticloadbalancing:AddTags
- elasticloadbalancing:RemoveTags
- elasticloadbalancing:ModifyLoadBalancerAttributes
- elasticloadbalancing:SetIpAddressType
- elasticloadbalancing:SetSecurityGroups
- elasticloadbalancing:SetSubnets
- elasticloadbalancing:DeleteLoadBalancer
- elasticloadbalancing:ModifyTargetGroup
- elasticloadbalancing:ModifyTargetGroupAttributes
- elasticloadbalancing:DeleteTargetGroup
- elasticloadbalancing:RegisterTargets
- elasticloadbalancing:DeregisterTargets
- elasticloadbalancing:SetWebAcl
- elasticloadbalancing:ModifyListener
- elasticloadbalancing:AddListenerCertificates
- elasticloadbalancing:RemoveListenerCertificates
- elasticloadbalancing:ModifyRule
Resource: '*'
# CloudWatch Log Group for EKS
EKSLogGroup:
Type: AWS::Logs::LogGroup
Properties:
LogGroupName: !Sub '/aws/eks/${EKSCluster}/cluster'
RetentionInDays: 7
Outputs:
ClusterName:
Description: EKS Cluster name
Value: !Ref EKSCluster
Export:
Name: !Sub '${AWS::StackName}-ClusterName'
ClusterArn:
Description: EKS Cluster ARN
Value: !GetAtt EKSCluster.Arn
Export:
Name: !Sub '${AWS::StackName}-ClusterArn'
ClusterEndpoint:
Description: EKS Cluster API endpoint
Value: !GetAtt EKSCluster.Endpoint
Export:
Name: !Sub '${AWS::StackName}-ClusterEndpoint'
ECRRepositoryUri:
Description: ECR Repository URI
Value: !Sub '${AWS::AccountId}.dkr.ecr.${AWS::Region}.amazonaws.com/${ECRRepository}'
Export:
Name: !Sub '${AWS::StackName}-ECRRepositoryUri'
FargatePodExecutionRoleArn:
Description: Fargate Pod Execution Role ARN
Value: !GetAtt FargatePodExecutionRole.Arn
Export:
Name: !Sub '${AWS::StackName}-FargatePodExecutionRoleArn'
LoadBalancerControllerRoleArn:
Description: IAM Role ARN for AWS Load Balancer Controller (IRSA)
Value: !GetAtt AWSLoadBalancerControllerRole.Arn
Export:
Name: !Sub '${AWS::StackName}-LBControllerRoleArn'