Skip to main content

第 10 章:EKS 設定

EKS Cluster

EKS cluster
resource "aws_eks_cluster" "example" {
name = "example"
role_arn = aws_iam_role.example.arn

vpc_config {
subnet_ids = [aws_subnet.example1.id, aws_subnet.example2.id]
}

# Ensure that IAM Role permissions are created before and deleted after EKS Cluster handling.
# Otherwise, EKS will not be able to properly delete EKS managed EC2 infrastructure such as Security Groups.
depends_on = [
aws_iam_role_policy_attachment.example-AmazonEKSClusterPolicy,
aws_iam_role_policy_attachment.example-AmazonEKSVPCResourceController,
]
}

output "endpoint" {
value = aws_eks_cluster.example.endpoint
}

output "kubeconfig-certificate-authority-data" {
value = aws_eks_cluster.example.certificate_authority[0].data
}
IAM Role for EKS Cluster
data "aws_iam_policy_document" "assume_role" {
statement {
effect = "Allow"

principals {
type = "Service"
identifiers = ["eks.amazonaws.com"]
}

actions = ["sts:AssumeRole"]
}
}

resource "aws_iam_role" "example" {
name = "eks-cluster-example"
assume_role_policy = data.aws_iam_policy_document.assume_role.json
}

resource "aws_iam_role_policy_attachment" "example-AmazonEKSClusterPolicy" {
policy_arn = "arn:aws:iam::aws:policy/AmazonEKSClusterPolicy"
role = aws_iam_role.example.name
}

# Optionally, enable Security Groups for Pods
# Reference: https://docs.aws.amazon.com/eks/latest/userguide/security-groups-for-pods.html
resource "aws_iam_role_policy_attachment" "example-AmazonEKSVPCResourceController" {
policy_arn = "arn:aws:iam::aws:policy/AmazonEKSVPCResourceController"
role = aws_iam_role.example.name
}
Enabling Control Plane Logging
variable "cluster_name" {
default = "example"
type = string
}

resource "aws_eks_cluster" "example" {
depends_on = [aws_cloudwatch_log_group.example]

enabled_cluster_log_types = ["api", "audit"]
name = var.cluster_name

# ... other configuration ...
}

resource "aws_cloudwatch_log_group" "example" {
# The log group name format is /aws/eks/<cluster-name>/cluster
# Reference: https://docs.aws.amazon.com/eks/latest/userguide/control-plane-logs.html
name = "/aws/eks/${var.cluster_name}/cluster"
retention_in_days = 7

# ... potentially other configuration ...
}
Enabling IAM Roles for Service Accounts
resource "aws_eks_cluster" "example" {
# ... other configuration ...
}

data "tls_certificate" "example" {
url = aws_eks_cluster.example.identity[0].oidc[0].issuer
}

resource "aws_iam_openid_connect_provider" "example" {
client_id_list = ["sts.amazonaws.com"]
thumbprint_list = [data.tls_certificate.example.certificates[0].sha1_fingerprint]
url = data.tls_certificate.example.url
}

data "aws_iam_policy_document" "example_assume_role_policy" {
statement {
actions = ["sts:AssumeRoleWithWebIdentity"]
effect = "Allow"

condition {
test = "StringEquals"
variable = "${replace(aws_iam_openid_connect_provider.example.url, "https://", "")}:sub"
values = ["system:serviceaccount:kube-system:aws-node"]
}

principals {
identifiers = [aws_iam_openid_connect_provider.example.arn]
type = "Federated"
}
}
}

resource "aws_iam_role" "example" {
assume_role_policy = data.aws_iam_policy_document.example_assume_role_policy.json
name = "example"
}
EKS Cluster with Access Config
resource "aws_iam_role" "example" {
assume_role_policy = data.aws_iam_policy_document.example_assume_role_policy.json
name = "example"
}

resource "aws_eks_cluster" "example" {
name = "example-cluster"
role_arn = aws_iam_role.example.arn

vpc_config {
endpoint_private_access = true
endpoint_public_access = false
# ... other configuration ...
}

access_config {
authentication_mode = "CONFIG_MAP"
bootstrap_cluster_creator_admin_permissions = true
}
}

EKS on Fargate

eks_fargate_profile
resource "aws_eks_fargate_profile" "example" {
cluster_name = aws_eks_cluster.example.name
fargate_profile_name = "example"
pod_execution_role_arn = aws_iam_role.example.arn
subnet_ids = aws_subnet.example[*].id

selector {
namespace = "example"
}
}
IAM Role for EKS Fargate Profile
resource "aws_iam_role" "example" {
name = "eks-fargate-profile-example"

assume_role_policy = jsonencode({
Statement = [{
Action = "sts:AssumeRole"
Effect = "Allow"
Principal = {
Service = "eks-fargate-pods.amazonaws.com"
}
}]
Version = "2012-10-17"
})
}

resource "aws_iam_role_policy_attachment" "example-AmazonEKSFargatePodExecutionRolePolicy" {
policy_arn = "arn:aws:iam::aws:policy/AmazonEKSFargatePodExecutionRolePolicy"
role = aws_iam_role.example.name
}

EKS node group

EKS node group
resource "aws_eks_node_group" "example" {
cluster_name = aws_eks_cluster.example.name
node_group_name = "example"
node_role_arn = aws_iam_role.example.arn
subnet_ids = aws_subnet.example[*].id

scaling_config {
desired_size = 1
max_size = 2
min_size = 1
}

update_config {
max_unavailable = 1
}

# Ensure that IAM Role permissions are created before and deleted after EKS Node Group handling.
# Otherwise, EKS will not be able to properly delete EC2 Instances and Elastic Network Interfaces.
depends_on = [
aws_iam_role_policy_attachment.example-AmazonEKSWorkerNodePolicy,
aws_iam_role_policy_attachment.example-AmazonEKS_CNI_Policy,
aws_iam_role_policy_attachment.example-AmazonEC2ContainerRegistryReadOnly,
]
}
Ignoring Changes to Desired Size
resource "aws_eks_node_group" "example" {
# ... other configurations ...

scaling_config {
# Example: Create EKS Node Group with 2 instances to start
desired_size = 2

# ... other configurations ...
}

# Optional: Allow external changes without Terraform plan difference
lifecycle {
ignore_changes = [scaling_config[0].desired_size]
}
}
Tracking the latest EKS Node Group AMI releases
data "aws_ssm_parameter" "eks_ami_release_version" {
name = "/aws/service/eks/optimized-ami/${aws_eks_cluster.example.version}/amazon-linux-2/recommended/release_version"
}

resource "aws_eks_node_group" "example" {
cluster_name = aws_eks_cluster.example.name
node_group_name = "example"
version = aws_eks_cluster.example.version
release_version = nonsensitive(data.aws_ssm_parameter.eks_ami_release_version.value)
node_role_arn = aws_iam_role.example.arn
subnet_ids = aws_subnet.example[*].id
}
IAM Role for EKS Node Group
resource "aws_iam_role" "example" {
name = "eks-node-group-example"

assume_role_policy = jsonencode({
Statement = [{
Action = "sts:AssumeRole"
Effect = "Allow"
Principal = {
Service = "ec2.amazonaws.com"
}
}]
Version = "2012-10-17"
})
}

resource "aws_iam_role_policy_attachment" "example-AmazonEKSWorkerNodePolicy" {
policy_arn = "arn:aws:iam::aws:policy/AmazonEKSWorkerNodePolicy"
role = aws_iam_role.example.name
}

resource "aws_iam_role_policy_attachment" "example-AmazonEKS_CNI_Policy" {
policy_arn = "arn:aws:iam::aws:policy/AmazonEKS_CNI_Policy"
role = aws_iam_role.example.name
}

resource "aws_iam_role_policy_attachment" "example-AmazonEC2ContainerRegistryReadOnly" {
policy_arn = "arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly"
role = aws_iam_role.example.name
}
Subnets for EKS Node Group
data "aws_availability_zones" "available" {
state = "available"
}

resource "aws_subnet" "example" {
count = 2

availability_zone = data.aws_availability_zones.available.names[count.index]
cidr_block = cidrsubnet(aws_vpc.example.cidr_block, 8, count.index)
vpc_id = aws_vpc.example.id
}

Eks Pod Identity Association

Eks Pod Identity Association
data "aws_iam_policy_document" "assume_role" {
statement {
effect = "Allow"

principals {
type = "Service"
identifiers = ["pods.eks.amazonaws.com"]
}

actions = [
"sts:AssumeRole",
"sts:TagSession"
]
}
}

resource "aws_iam_role" "example" {
name = "eks-pod-identity-example"
assume_role_policy = data.aws_iam_policy_document.assume_role.json
}

resource "aws_iam_role_policy_attachment" "example_s3" {
policy_arn = "arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess"
role = aws_iam_role.example.name
}

resource "aws_eks_pod_identity_association" "example" {
cluster_name = aws_eks_cluster.example.name
namespace = "example"
service_account = "example-sa"
role_arn = aws_iam_role.example.arn
}

EKS Access Entry

EKS Access Entry
resource "aws_eks_access_entry" "example" {
cluster_name = aws_eks_cluster.example.name
principal_arn = aws_iam_role.example.arn
kubernetes_groups = ["group-1", "group-2"]
}

Access Policy Association

Access Policy Association
resource "aws_eks_access_policy_association" "example" {
cluster_name = aws_eks_cluster.example.name
policy_arn = "arn:aws:eks::aws:cluster-access-policy/AmazonEKSViewPolicy"
principal_arn = aws_iam_user.example.arn

access_scope = {
type = "namespace"
namespaces = ["example-namespace"]
}
}

EKS Addon

EKS Addon
resource "aws_eks_addon" "example" {
cluster_name = aws_eks_cluster.example.name
addon_name = "vpc-cni"
}
IAM Role for EKS Addon "vpc-cni" with AWS managed policy
resource "aws_eks_cluster" "example" {
# ... other configuration ...
}

data "tls_certificate" "example" {
url = aws_eks_cluster.example.identity[0].oidc[0].issuer
}

resource "aws_iam_openid_connect_provider" "example" {
client_id_list = ["sts.amazonaws.com"]
thumbprint_list = [data.tls_certificate.example.certificates[0].sha1_fingerprint]
url = aws_eks_cluster.example.identity[0].oidc[0].issuer
}

data "aws_iam_policy_document" "example_assume_role_policy" {
statement {
actions = ["sts:AssumeRoleWithWebIdentity"]
effect = "Allow"

condition {
test = "StringEquals"
variable = "${replace(aws_iam_openid_connect_provider.example.url, "https://", "")}:sub"
values = ["system:serviceaccount:kube-system:aws-node"]
}

principals {
identifiers = [aws_iam_openid_connect_provider.example.arn]
type = "Federated"
}
}
}

resource "aws_iam_role" "example" {
assume_role_policy = data.aws_iam_policy_document.example_assume_role_policy.json
name = "example-vpc-cni-role"
}

resource "aws_iam_role_policy_attachment" "example" {
policy_arn = "arn:aws:iam::aws:policy/AmazonEKS_CNI_Policy"
role = aws_iam_role.example.name
}