商用環境を想定したEKSの構成を試してみた
動機
EKSのControl Planeへのアクセスが公開されている状態で商用環境の運用を行うことはリスクを鑑みると望ましい状況とは言えない。
パブリックアクセスが有効化されている状態であっても当該AWSアカウントへのアクセスができる状態にないと基本的には操作できないとはいえ、顧客の要求やリスク排除を考慮するとやはりエンドポイントは公開しないことが望ましい。
ということでEKSへのパブリックアクセスを無効化しつつ、踏み台を用意して(比較的)安全に操作する手段を構築したので書き留めておく。
成果物
構成
ざっくりした構成図は以下。
直接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