🎧

商用環境を想定したEKSの構成を試してみた

2024/05/07に公開

動機

EKSのControl Planeへのアクセスが公開されている状態で商用環境の運用を行うことはリスクを鑑みると望ましい状況とは言えない。
パブリックアクセスが有効化されている状態であっても当該AWSアカウントへのアクセスができる状態にないと基本的には操作できないとはいえ、顧客の要求やリスク排除を考慮するとやはりエンドポイントは公開しないことが望ましい。

ということでEKSへのパブリックアクセスを無効化しつつ、踏み台を用意して(比較的)安全に操作する手段を構築したので書き留めておく。

成果物

https://github.com/anizozina/eks-entry

構成

ざっくりした構成図は以下。

直接EKSを操作する場合は、Cloud9を踏み台としてEKSに対してリクエストを流し込む流れになる。
基本的な運用としてはGitOpsでNode内に展開したArgoCD経由で展開する流れを想定している。

また、Node groupはEC2ではなくFargateを選択している。
セキュリティパッチの適用などインスタンスレベルでの運用をしなくても良いように。
その分お金がかかるのでコスト試算は大事。

解説

手作業と自動化のスコープ

手作業は可能な限り排除したいと願いつつも以下に列挙する作業は残ってしまった。

  • Cloud9 にアクセスするユーザーの作成
  • Cloud9 上で行うArgoCDの作業
  • ArgoCDのALBに紐づけるドメイン・証明書の管理
  • ArgoCD上で行うリポジトリの設定

おそらくいくつかは自動化できる余地がありそうだと思いつつ触れていない。

Cloud9の構築

今回は connection_type に CONNECT_SSM を指定している通り、いわゆる no-ingress EC2 環境として構成している。
ref. https://docs.aws.amazon.com/ja_jp/cloud9/latest/user-guide/ec2-ssm.html

そのため、コンソール上でCluod9の環境を作成すると暗黙的にやってくれているIAMの作成をコードで表現しなければならない。
ref. https://docs.aws.amazon.com/ja_jp/cloud9/latest/user-guide/using-service-linked-roles.html

成果物のコードでは cloud9.tf で表現されている部分。
Cloud9の環境が複数あるAWSアカウントだとおそらく余計な作業になりかねないがその考慮はできていない。

VPCの設定

Cloud9にアクセするために、Public subnetにはIPv4の自動割り当てを有効化する必要がある。
ref. https://github.com/anizozina/eks-entry/blob/main/terraform/vpc.tf#L24

自動割り当てを有効化しないと Cloud9 could not connect to the EC2 instance. Please check your VPC configuration and network settings to troubleshoot the issue 的なエラーで怒られる。
ref. https://tetsuyaohira.com/posts/2022-11-26-cloud9-error/

EKSの設定

今回は商用環境をfargateに展開したPodで行う想定。
ArgoCDとアプリの名前空間を分離して衝突が起こらないようにしている。
ref. https://github.com/anizozina/eks-entry/blob/main/terraform/eks.tf#L19-L47

また、Cloud9からClusterへのアクセスはSecurity Groupで許可を出してあげる必要がある。
ref. https://github.com/anizozina/eks-entry/blob/main/terraform/eks.tf#L89C32-L105

ArgoCDの作成

terraform 適用後、Cloud9のログインURLをoutputするようにしている。
作成したIAM Userでログインをすると、IDEが使えるようになっているのでTerminal上で諸々の操作を行う。
環境はまっさらなので必要なツールを都度入れていく必要がある。
kubectl

curl -O https://s3.us-west-2.amazonaws.com/amazon-eks/1.29.0/2024-01-04/bin/linux/amd64/kubectl
chmod +x ./kubectl
mkdir -p $HOME/bin && cp ./kubectl $HOME/bin/kubectl && export PATH=$HOME/bin:$PATH
echo 'export PATH=$HOME/bin:$PATH' >> ~/.bashrc

Cluster名は適宜Terraformからとってくるとして、kubectlの設定更新

aws eks update-kubeconfig --region ap-northeast-1 --name $cluster_name

helm

curl https://raw.githubusercontent.com/helm/helm/master/scripts/get-helm-3 > get_helm.sh
chmod 700 get_helm.sh
./get_helm.sh

ALBC経由でLoad Balancerを作成するのでService Accountと一緒に作る。
VPC_IDとIAM ROLEのARNはterraformのoutputから取得する。

helm repo add eks https://aws.github.io/eks-charts
helm repo update eks

helm install aws-load-balancer-controller eks/aws-load-balancer-controller \
  -n kube-system \
  --set clusterName=eks-investigation \
  --set serviceAccount.create=true \
  --set serviceAccount.name=aws-load-balancer-controller \
  --set serviceAccount.annotations."eks\.amazonaws\.com/role-arn"="$role_arn" \
  --set region=ap-northeast-1 \
  --set vpcId=$vpc_id

ArgoCD CLI

curl -sSL -o argocd-linux-amd64 https://github.com/argoproj/argo-cd/releases/latest/download/argocd-linux-amd64
sudo install -m 555 argocd-linux-amd64 /usr/local/bin/argocd
rm argocd-linux-amd64

名前空間の作成

kubectl create namespace argocd 

ArgoCDへアクセスできるようにする。
まずは定義を取得する。

curl -O https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml

このままだとALBのHealth Checkが通らないのでkustomizeでpatchを適用する。
ref. https://qiita.com/Ichi0124/items/bc37ad6f4aad9c3b9360
install-patch.yml的な名前でファイルを作成。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: argocd-server
spec:
  selector:
    matchLabels:
      app.kubernetes.io/name: argocd-server
  template:
    spec:
      containers:
      - args: 
        - /usr/local/bin/argocd-server
        - --insecure
        name: argocd-server

kustomization.ymlも作っておく

apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: argocd
resources:
- ./install.yaml
- ./ingress.yml
patchesStrategicMerge:
- ./install-patch.yml

最後にALB作成用のingress.ymlも作成する。
ドメインと証明書のARNは事前に作っておいたものを指定している。

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: argocd-ingress
  namespace: argocd
  annotations:
    alb.ingress.kubernetes.io/scheme: internet-facing
    alb.ingress.kubernetes.io/target-type: 'ip'
    alb.ingress.kubernetes.io/backend-protocol-version: HTTP1
    alb.ingress.kubernetes.io/healthcheck-path: /healthz
    alb.ingress.kubernetes.io/success-codes: '200'
    alb.ingress.kubernetes.io/listen-ports: '[{"HTTP":80,"HTTPS": 443}]'
    alb.ingress.kubernetes.io/actions.ssl-redirect: '{"Type": "redirect", "RedirectConfig": { "Protocol": "HTTPS", "Port": "443", "StatusCode": "HTTP_301"}}'
    alb.ingress.kubernetes.io/certificate-arn: $acm_arn
  finalizers:
    - ingress.k8s.aws/resources
  labels:
    app: argocd-ingress
spec:
  ingressClassName: alb
  rules:
  - host: $domain
    http:
      paths:
        - path: /
          backend:
            service:
              name: argocd-server
              port:
                number: 80
          pathType: Prefix
  tls:
  - hosts:
    - $domain

kubectl apply -k ./ -n argocd でリソースができるはずなので、 argocd --namespace argocd admin initial-password で adminユーザーのパスワードを取得してログインする。

ArgoCD上の設定はここでは述べないが、パブリックリポジトリに対して設定を組んでみたら視覚的に見えるようになったのでめちゃめちゃ有用だなぁという感想を持った。

おわりに

Cloud9を立てるのが良いか、EC2のインスタンスを立てるのが良いのか自分のなかで決着はついていない。
どっちも一度AWSコンソールへのアクセスをしないといけない時点で面倒だなぁと言う気持ちが生まれてしまうので..。
ただCloud9はユーザーへのアクセス権付与・剥奪がEC2よりも柔軟かも、という予感がある。アプリケーションに近いレイヤでの制御なので。

本筋ではないが、ArgoCDの設定の簡便さと視認性の良さはかなり驚いた。これないと運用できない気すらしてきてる。ので今回ArgoCDも触れて良かった〜〜。

もし改善点やツッコミがあればいただけると嬉しいです 🙏

Discussion