0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

EKSマネージドワーカーに任意のセキュリティグループをつける

Posted at

EKSのマネージドワーカーはとても便利ですがデプロイされるEC2につくセキュリティグループはEKSが作成したものです。自分で作成した任意のセキュリティグループを付与するにはEC2の起動テンプレートを作成し、その中でセキュリティグループを指定します。

これをTerraformで設定する方法を残しておきます。

マネージドノードグループが作成する起動テンプレートの確認

Terraformで作成する起動テンプレートの参考にするためまずは普通にマネージドワーカーをデプロイして設定を確認します。

マネージメントコンソールなどからマネージドノードグループが作成する起動テンプレートのIDを確認します。たとえばマネージメントコンソールからだとEC2->インタンス->テンプレートの起動に起動テンプレートはあります。またはEC2->Auto ScalingグループでEKSマネージドノードグループのオートスケーリンググループから確認しても良いです。

マネージメントコンソールからでも起動テンプレートの設定を確認できるが念の為コマンドで設定を確認します。

$ aws ec2 describe-launch-template-versions --launch-template-id lt-084a093919e4b2c36

出力例

{
    "LaunchTemplateVersions": [
        {
            "LaunchTemplateId": "lt-084a093919e4b2c36",
            "LaunchTemplateName": "eks-08bd9e75-1ab5-77ea-3e5e-96f926cdda77",
            "VersionNumber": 1,
            "CreateTime": "2021-08-13T00:30:03+00:00",
            "CreatedBy": "arn:aws:sts::461548955069:assumed-role/AWSServiceRoleForAmazonEKSNodegroup/EKS",
            "DefaultVersion": true,
            "LaunchTemplateData": {
                "IamInstanceProfile": {
                    "Name": "eks-08bd9e75-1ab5-77ea-3e5e-96f926cdda77"
                },
                "BlockDeviceMappings": [
                    {
                        "DeviceName": "/dev/xvda",
                        "Ebs": {
                            "DeleteOnTermination": true,
                            "VolumeSize": 30,
                            "VolumeType": "gp2"
                        }
                    }
                ],
                "NetworkInterfaces": [
                    {
                        "DeviceIndex": 0,
                        "Groups": [
                            "sg-0bd04e1bd3c43d395",
                            "sg-0195e42ca26f31d49"
                        ]
                    }
                ],
                "ImageId": "ami-02a49655b336f1b47",
                "InstanceType": "t3.medium",
                "KeyName": "hoge",
                "UserData": "TUlNRS1WZXJzaW...,
                "MetadataOptions": {
                    "HttpPutResponseHopLimit": 2
                }
            }
        }
    ]
}

userdataをbase64デコードすると以下の内容

MIME-Version: 1.0
Content-Type: multipart/mixed; boundary="//"

--//
Content-Type: text/x-shellscript; charset="us-ascii"
#!/bin/bash
set -ex
B64_CLUSTER_CA=LS0tLS1CRUdJTiBDRVJUSUZ...
API_SERVER_URL=https://B575989085247853299602E94FEED13C.gr7.ap-northeast-1.eks.amazonaws.com
K8S_CLUSTER_DNS_IP=172.20.0.10
/etc/eks/bootstrap.sh o2-dev-cluster --kubelet-extra-args '--node-labels=eks.amazonaws.com/nodegroup-image=ami-02a49655b336f1b47,eks.amazonaws.com/capacityType=ON_DEMAND,eks.amazonaws.com/nodegroup=o2-dev-node-group' --b64-cluster-ca $B64_CLUSTER_CA --apiserver-endpoint $API_SERVER_URL --dns-cluster-ip $K8S_CLUSTER_DNS_IP

--//--

上記結果を参考にTerraformを作成します。

Terraform

Terraformは以下5種類とvariablesを作成します。

  • iam.tf
  • managed-node-group.tf
  • launch-config.tf
  • sg.tf
  • eks.tf
  • variables.tf

iam.tf

EKSおよびマネージドノードグループに必要なIAMを作成します。元ネタはAWSドキュメントにあるAmazon EKS クラスター の IAM ロールAmazon EKS ノードの IAM ロールを参考にしています。

iam.tf
# eks cluster
resource "aws_iam_role" "eks_cluster" {
  name = "${var.base_name}-eks-cluster-role"

  assume_role_policy = <<POLICY
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Service": "eks.amazonaws.com"
      },
      "Action": "sts:AssumeRole"
    }
  ]
}
POLICY

  tags = {
    "Name" = "${var.base_name}-eks-cluster-role"
  }
}

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

resource "aws_iam_role_policy_attachment" "eks_vpc_resource_controller" {
  policy_arn = "arn:aws:iam::aws:policy/AmazonEKSVPCResourceController"
  role       = aws_iam_role.eks_cluster.name
}

# managed node group
resource "aws_iam_role" "eks_node_group" {
  name = "${var.base_name}-eks-node-group"

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

  tags = {
    "Name" = "${var.base_name}-eks-node-group"
  }
}

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

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

resource "aws_iam_role_policy_attachment" "ec2_ecr_ro" {
  policy_arn = "arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly"
  role       = aws_iam_role.eks_node_group.name
}

managed-node-group.tf

マネージドノードグループの設定をします。ここで任意のセキュリティグループを付けたいため、launch_templateを指定します。また、eks-node-group.tflaunch-config.tfにはいつくか両方ともで設定できるパラメータがあります。そのようなパラメータを両方で設定するとエラーになるため一方でのみ設定します。どちらで設定すべきかはAWSのドキュメント起動テンプレートのサポートに案内があります。

managed-node-group.tf
resource "aws_eks_node_group" "worker" {
  cluster_name    = var.eks_name
  node_group_name = "${var.base_name}-node-group"
  node_role_arn   = aws_iam_role.eks_node_group.arn
  subnet_ids      = var.public_subnet_ids

  launch_template {
    id      = aws_launch_template.eks_node_group.id
    version = aws_launch_template.eks_node_group.latest_version
  }

  scaling_config {
    desired_size = var.eks-node_desired_capacity
    max_size     = var.eks-node_max_size
    min_size     = var.eks-node_min_size
  }

  tags = {
    "Name" = "${var.base_name}-node-group"
  }

  lifecycle {
    ignore_changes = [scaling_config[0].desired_size]
  }

  depends_on = [
    aws_eks_cluster.this
  ]
}

launch-config.tf

起動テンプレートの設定をします。基本的には[マネージドノードグループが作成する起動テンプレートの確認](#マネージドノードグループが作成する起動テンプレートの確認で確認した内容をそのままTerraformに落とし込んでいます。

network_interfacesに目的である任意のセキュリティグループを指定します。また、EKSマスターと通信するためのセキュリティグループも必要です。(元ネタ:カスタムセキュリティグループを使用する

USERDATAの中でK8S_CLUSTER_DNS_IPを指定しています。これはCoreDNSのServiceのIPアドレスですが、ServiceネットワークのCIDRによってIPアドレスが異なります。デフォルトのServiceネットワークのCIDRはTerraformのaws_eks_clusterリソースのドキュメントkubernetes_network_configにある通り、EKSをデプロイするVPCのCIDRとは異なるCIDR(10.100.0.0/16 or 172.20.0.0/16)を使用します。今回はEKSの設定でservice_ipv4_cidrを指定し、そのvaluesを加工してCoreDNSのServiceのIPアドレスを指定しています。

launch-config.tf
locals {
  eks-nodes_init_script = <<USERDATA
MIME-Version: 1.0
Content-Type: multipart/mixed; boundary="//"

--//
Content-Type: text/x-shellscript; charset="us-ascii"
#!/bin/bash
set -ex
B64_CLUSTER_CA=${aws_eks_cluster.this.certificate_authority.0.data}
API_SERVER_URL=${aws_eks_cluster.this.endpoint}
K8S_CLUSTER_DNS_IP=${replace(var.eks_service_ipv4_cidr, "0/16", "10")}
/etc/eks/bootstrap.sh ${var.eks_name} --kubelet-extra-args '--node-labels=eks.amazonaws.com/nodegroup-image=${data.aws_ami.eks-node.id},eks.amazonaws.com/capacityType=ON_DEMAND,eks.amazonaws.com/nodegroup=${var.base_name}-node-group' --b64-cluster-ca $B64_CLUSTER_CA --apiserver-endpoint $API_SERVER_URL --dns-cluster-ip $K8S_CLUSTER_DNS_IP

--//--
USERDATA
}

data "aws_ami" "eks-node" {
  most_recent = true
  owners      = ["602401143452"]

  filter {
    name   = "name"
    values = ["amazon-eks-node-${var.eks_version}-*"]
  }
}

resource "aws_launch_template" "eks_node_group" {
  name = "${var.base_name}-eks_node_group"

  block_device_mappings {
    device_name = "/dev/xvda"

    ebs {
      delete_on_termination = true
      volume_size           = var.eks-node_volume_size
      volume_type           = "gp2"
    }
  }

  network_interfaces {
    device_index    = 0
    security_groups = [aws_security_group.eks-node.id, aws_security_group.eks.id]
  }

  image_id      = data.aws_ami.eks-node.id
  instance_type = var.eks-node_instance_type
  key_name      = var.eks-node_key_name
  user_data     = base64encode(local.eks-nodes_init_script)

  depends_on = [
    aws_eks_cluster.this
  ]

  tags = {
    "Name" = "${var.base_name}-eks_node_group"
  }
}

sg.tf

セキュリティグループを設定します。カスタムセキュリティグループを使用するにある通り、マネージドノードに付けたいセキュリティグループとEKSマスターと通信するためのセキュリティグループを作ります。

セキュリティグループのルールはAmazon EKS セキュリティグループの考慮事項を参考にします。

sg.tf
# eks cluster
resource "aws_security_group" "eks" {
  name        = "${var.base_name}-eks-sg"
  description = "for eks sg"
  vpc_id      = var.vpc_id

  tags = {
    "Name" = "${var.base_name}-eks-sg",
  }
}

resource "aws_security_group_rule" "eks_in_443_self" {
  type              = "ingress"
  from_port         = 443
  to_port           = 443
  protocol          = "tcp"
  self              = true
  security_group_id = aws_security_group.eks.id
}

resource "aws_security_group_rule" "eks_in_1025-65535_self" {
  type              = "ingress"
  from_port         = 1025
  to_port           = 65535
  protocol          = "tcp"
  self              = true
  security_group_id = aws_security_group.eks.id
}

resource "aws_security_group_rule" "eks_out_all" {
  type              = "egress"
  from_port         = 0
  to_port           = 0
  protocol          = "-1"
  cidr_blocks       = ["0.0.0.0/0"]
  ipv6_cidr_blocks  = ["::/0"]
  security_group_id = aws_security_group.eks.id
}

# managed node group
resource "aws_security_group" "eks-node" {
  name        = "${var.base_name}-eks-node-sg"
  description = "for eks-node server sg"
  vpc_id      = var.vpc_id

  tags = {
    "Name"                                  = "${var.base_name}-eks-node-sg",
    "kubernetes.io/cluster/${var.eks_name}" = "owned"
  }
}

resource "aws_security_group_rule" "eks-node_in_30000-65535" {
  type              = "ingress"
  from_port         = 30000
  to_port           = 65535
  protocol          = "tcp"
  cidr_blocks       = ["0.0.0.0/0"]
  security_group_id = aws_security_group.eks-node.id
}

resource "aws_security_group_rule" "eks-node_in_self" {
  type              = "ingress"
  from_port         = 0
  to_port           = 0
  protocol          = -1
  self              = true
  security_group_id = aws_security_group.eks-node.id
}

resource "aws_security_group_rule" "eks-node_out_all" {
  type              = "egress"
  from_port         = 0
  to_port           = 0
  protocol          = "-1"
  cidr_blocks       = ["0.0.0.0/0"]
  ipv6_cidr_blocks  = ["::/0"]
  security_group_id = aws_security_group.eks-node.id
}

eks.tf

EKSの設定です。マネージドワーカーと通信するため、security_group_idsに作成したEKSクラスタ用のセキュリティグループを指定します。また、launch-configtfのUSERDATAでCoreDNSのIPアドレスを指定したいため、kubernetes_network_configも設定します。

eks.tf
resource "aws_eks_cluster" "this" {
  name     = var.eks_name
  role_arn = aws_iam_role.eks_cluster.arn
  version  = var.eks_version

  vpc_config {
    endpoint_private_access = var.eks_endpoint_private_access
    endpoint_public_access  = var.eks_endpoint_public_access
    public_access_cidrs     = var.eks_public_access_cidrs
    security_group_ids      = [aws_security_group.eks.id]
    subnet_ids              = flatten([var.private_subnet_ids, var.public_subnet_ids])
  }

  enabled_cluster_log_types = var.eks_enabled_cluster_log_types

  kubernetes_network_config {
    service_ipv4_cidr = var.eks_service_ipv4_cidr
  }

  tags = {
    "Name" = var.eks_name
  }

  depends_on = [
    aws_iam_role_policy_attachment.eks_cluster,
    aws_iam_role_policy_attachment.eks_vpc_resource_controller,
  ]
}

variables.tf

variables.tf
variable "base_name" {
  description = "作成するリソースに付与する接頭語"
  type        = string
}

## EKS
variable "eks_version" {
  description = "EKSのバージョン"
  type        = string
}

variable "eks_name" {
  description = "EKSクラスタの名前"
  type        = string
}

variable "eks_endpoint_private_access" {
  description = "VPC内からのアクセスを許可するか"
  type        = bool
}

variable "eks_endpoint_public_access" {
  description = "VPC外からのアクセスを許可するか"
  type        = bool
}

variable "eks_public_access_cidrs" {
  description = "VPC外からのアクセスを許可するCIDR"
  type        = list(string)
}

variable "eks_enabled_cluster_log_types" {
  description = "保存するマスターコンポーネントのログ"
  type        = list(string)
}

variable "eks_service_ipv4_cidr" {
  description = "serviceのCIDR"
  type        = string
}

## EKS node group
variable "eks-node_desired_capacity" {
  description = "EKSノードグループの希望数"
  type        = number
}

variable "eks-node_max_size" {
  description = "EKSノードグループの最大数"
  type        = number
}

variable "eks-node_min_size" {
  description = "EKSノードグループの最小数"
  type        = number
}

variable "eks-node_volume_size" {
  description = "EKSノードのディスク容量"
  type        = number
}

variable "eks-node_instance_type" {
  description = "EKSノードのインスタンスタイプ"
  type        = string
}

variable "eks-node_key_name" {
  description = "EKSノードのキーペア名"
  type        = string
}

tfvarsの例

# common parameter
base_name = "test-eks"

# network parameter
private_subnet_ids = [
  "subnet-04e80b9b64g8ab944",
  "subnet-05dec3759d2ff895a",
]
public_subnet_ids = [
  "subnet-0fd24b7b1d9f11078",
  "subnet-0e12b21b7fc7ccf77",
]
vpc_cidr = "10.1.0.0/16"
vpc_id   = "vpc-0b02175fcb37cb133"

# eks cluster
eks_version                   = "1.21"
eks_name                      = "test-eks-cluster"
eks_endpoint_private_access   = true
eks_endpoint_public_access    = true
eks_public_access_cidrs       = ["126.72.69.141/32"]
eks_enabled_cluster_log_types = ["api", "audit", "authenticator", "controllerManager", "scheduler"]
eks_service_ipv4_cidr         = "172.20.0.0/16"

# eks node group
eks-node_desired_capacity = 4
eks-node_max_size         = 4
eks-node_min_size         = 4
eks-node_volume_size      = 30
eks-node_instance_type    = "m5.large"
eks-node_key_name         = "hoge"

あとがき

オートスケーリンググループが使用する起動テンプレートは上記自分で作成した起動テンプレートではなく、自分で作成したテンプレートをコピーして新たに作られる起動テンプレートが使用されるようです。マネージドノードグループの設定でテンプレートのバージョンをlatestで指定していれば自分で作成したテンプレートを更新するとコピーの起動テンプレートも更新されました。

ただ、ここまでいろいろやるならセルフマネージドのオートスケーリンググループ作るのとあんまり変わらない気もした。

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?