以下の構成を作成し、Cognito 認証を終えたトラフィックのみ eks の世界に到達できるようにします。
環境
Kubernetes バージョン : 1.14
AWS ALB Ingress Controller バージョン : v1.1.5
EKS クラスター作成
- まずクラスターを作成
eksctl create cluster --name=k8s-cluster
ALB Ingress Controller のデプロイ
- Ingress リソースがデプロイされたタイミングで ALB を作成させる
-
IAM OIDC(OpenID Connect) プロバイダーを作成してクラスターに関連付ける
- k8s 内のリソース ServiceAccount と IAM の橋渡しをさせる
- 参考: [アップデート] EKS で IAM ロールを使った Pod 単位のアクセス制御が可能になりました!
$ eksctl utils associate-iam-oidc-provider --region=ap-northeast-1 --cluster=k8s-cluster --approve
AWS IAM => ID プロバイダーを確認し、タイプ OpenIDConnect のプロバイダが作成されていることを確認
-
ALB Ingress Controller Pod にアタッチする IAM ポリシー作成
aws iam create-policy \ --policy-name ALBIngressControllerIAMPolicy \ --policy-document https://kubernetes-sigs.github.io/aws-alb-ingress-controller/examples/iam-policy.json
-
返ってきたARNを控える
{ "Policy": { "PolicyName": "ALBIngressControllerIAMPolicy", "PermissionsBoundaryUsageCount": 0, "AttachmentCount": 0, "IsAttachable": true, "PolicyId": "POLICYID", "DefaultVersionId": "v1", "Path": "/", "Arn": "{ALBIngressControllerIAMPolicyのARN}" } }
-
ALB Ingress Controller マニフェストを DL
wget https://raw.githubusercontent.com/kubernetes-sigs/aws-alb-ingress-controller/v1.1.5/docs/examples/alb-ingress-controller.yaml
-
クラスター名を作成したクラスター名に編集
- --cluster-name=k8s-cluster
-
RBAC ロールマニフェストをデプロイする
kubectl apply -f https://raw.githubusercontent.com/kubernetes-sigs/aws-alb-ingress-controller/v1.1.5/docs/examples/rbac-role.yaml
-
作成したサービスアカウントに IAM ポリシーをアタッチする
eksctl create iamserviceaccount \ --region ap-northeast-1 \ --name alb-ingress-controller \ --namespace kube-system \ --cluster k8s-cluster \ --attach-policy-arn {さっき控えたALBIngressControllerIAMPolicyのARN} \ --override-existing-serviceaccounts \ --approve
-
ALB Ingress Controller をデプロイする
kubectl apply -f alb-ingress-controller.yaml
-
ALB Ingress Controller の作成を確認
kubectl logs -n kube-system $(kubectl get po -n kube-system | egrep -o "alb-ingress[a-zA-Z0-9-]+")
ExternalDNS のデプロイ
- ingress リソースのホスト情報に基づいて DNS レコードをプロビジョニングする
- alb-ingress-controller がデプロイした ALB を指す Route 53 のレコードを作成する
-
IAM ポリシー(AllowExternalDNSUpdates)を作成
- ExternalDNSPod に Route53 リソースレコードセットとホストゾーンを更新させるために IAM ポリシーを作成
- IAM ポリシーの元ネタを get
aws iam create-policy --policy-name AllowExternalDNSUpdates --policy-document file://AllowExternalDNSUpdates.json
-
返ってきたARNを控える
{ "Policy": { "PolicyName": "AllowExternalDNSUpdates", "PermissionsBoundaryUsageCount": 0, "AttachmentCount": 0, "IsAttachable": true, "PolicyId": "POLICYID", "DefaultVersionId": "v1", "Path": "/", "Arn": "{AllowExternalDNSUpdatesのARN}" } }
-
サービスアカウント(external-dns)と IAM ロールを作成
eksctl create iamserviceaccount \ --region ap-northeast-1 \ --name external-dns \ --namespace kube-system \ --cluster k8s-cluster \ --attach-policy-arn {AllowExternalDNSUpdatesのARN} \ --override-existing-serviceaccounts \ --approve
IAM -> ポリシー AllowExternalDNSUpdates -> ポリシーの使用状況タブを見て、ロールが作成されていることを確認
-
Route 53 ホストゾーンを設定する
- public に レコードと SOA レコードを作成する
-
ExternalDNS を deploy する
- externaldns.yaml の元ネタを get する
- externaldns の ServiceAccount の annotaions に AllowExternalDNSUpdates ポリシーがアタッチされているロールの arn を記載する
-
$ kubectl apply -f externaldns.yaml
-
ExternalDNS の作成を確認
kubectl logs -n kube-system $(kubectl get po -n kube-system | egrep -o "external-dns[a-zA-Z0-9-]+")
-
ExternalDNSPod にロールがアタッチされていることを確認
kubectl exec -n kube-system external-dns-576fb7578c-zmvlt env | grep AWS AWS_ROLE_ARN={ロールのarn}
Cognito / ALB Ingress Controller のセットアップ
- Cognito ユーザープール作成
-
ベースはインフラエンジニアが一切コードを書かずにWebサーバーに認証機能を実装した話をみつつ作成する
- アプリクライアントのシークレットを生成するに
- ALLOW_USER_PASSWORD_AUTH にチェック
-
Certificate Manger (バージニア北部) にてドメインの証明書を発行する
- 証明書を Cognito でリクエストまたはインポートするには、ACM コンソールで AWS リージョンを米国東部 (バージニア北部) に変更する必要がある。
-
Route53 でサブドメイン無しの A レコードを適当に設定
- 1.1.1.1 とかでも よい
-
アプリケーション統合の構成
- Callback URL
https://<your-domain>/oauth2/idpresponse
- 許可されている OAuth フロー
- Authorization code grant
- 許可されている OAuth スコープ
- openid
- ドメイン名
auth.<your-domain>
- AWS マネージド証明書に CM(バージニア北部)で発行した証明書を指定
- Callback URL
-
ドメインのステータスが 15 分程度かかって Active になったらドメイン名とエイリアスターゲットを Route53 に登録する
- タイプ CNAME
- 例) auth. → xxxxxxxxxxxxxx.cloudfront.net
Ingress をデプロイ
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: "ingress"
annotations:
kubernetes.io/ingress.class: alb
alb.ingress.kubernetes.io/scheme: internet-facing
alb.ingress.kubernetes.io/listen-ports: '[{"HTTP": 80}, {"HTTPS": 443}]'
# ドメインの証明書のarn
alb.ingress.kubernetes.io/certificate-arn: {ドメインの証明書のarn}
# http -> https のリダイレクト
alb.ingress.kubernetes.io/actions.ssl-redirect: '{"Type": "redirect", "RedirectConfig": { "Protocol": "HTTPS", "Port": "443", "StatusCode": "HTTP_301"}}'
# Authentication type must be cognito
alb.ingress.kubernetes.io/auth-type: cognito
# Required parameter for ALB/Cognito integration
alb.ingress.kubernetes.io/auth-scope: openid
# Session timeout on authentication credentials
alb.ingress.kubernetes.io/auth-session-timeout: '3600'
# Session cookie name
alb.ingress.kubernetes.io/auth-session-cookie: AWSELBAuthSessionCookie
# Action to take when a request is not authenticated
alb.ingress.kubernetes.io/auth-on-unauthenticated-request: authenticate
# Cognito parameters required for creation of authentication rules
# The subdomain name only is sufficient for `UserPoolDomain`
# e.g. if `FQDN=app.auth.ap-northeast-1.amazoncognito.com` then `UserPoolDomain=app`
alb.ingress.kubernetes.io/auth-idp-cognito: '{"UserPoolArn": "arn:aws:cognito-idp:<region>:<account-id>:userpool/<region><cognito-id>","UserPoolClientId":"<user-pool-client-id>","UserPoolDomain":"<user-pool-authentication-domain>"}'
labels:
app: ingress
spec:
rules:
- host: <your-domain>
http:
paths:
- path: /*
backend:
serviceName: "bff-service"
servicePort: 3000
-
ドメインの証明書の arn(alb.ingress.kubernetes.io/certificate-arn) を変更
- クラスターのあるリージョンで申請した SSL 証明書の ARN を設定しないとエラーがでた
-
Cognito 設定(alb.ingress.kubernetes.io/auth-idp-cognito)を変更
kubectl apply -f ingress.yaml
確認(alb リソースなど完全にできるまで時間がかかる)
アプリをデプロイ
アプリは適当に好きなマニフェストでやってください
-
backend deploy
- kubectl apply -f backend.yaml
backend.yaml 例
################################################################################################## # backend services ################################################################################################## apiVersion: v1 kind: Service metadata: name: backend spec: type: ClusterIP # クラスタ内でのみ利用可能 ports: - name: http protocol: TCP port: 8080 targetPort: 8080 selector: app: backend-pod # 転送先Podを設定 --- apiVersion: v1 kind: ServiceAccount metadata: name: backend-serviceaccount --- apiVersion: apps/v1 kind: Deployment metadata: name: backend-deployment spec: replicas: 2 selector: matchLabels: app: backend-pod version: v1 template: metadata: labels: app: backend-pod version: v1 spec: serviceAccountName: backend-serviceaccount containers: - name: backend-container image: { container_url } imagePullPolicy: Always ports: - containerPort: 8080 ---
-
bff deploy
- kubectl apply -f bff.yaml
bff.yaml 例
################################################################################################## # bff service ################################################################################################## apiVersion: v1 kind: Service metadata: name: "bff-service" spec: type: NodePort # k8sノードのIP:Portで受けたトラフィックをコンテナに転送する ports: - protocol: TCP port: 3000 targetPort: 3000 selector: app: "bff-pod" # 転送先Podを設定 --- apiVersion: v1 kind: ServiceAccount metadata: name: bff-serviceaccount --- apiVersion: apps/v1 kind: Deployment metadata: name: bff-deployment spec: replicas: 2 selector: matchLabels: app: bff-pod version: v1 template: metadata: labels: app: bff-pod version: v1 spec: serviceAccountName: bff-serviceaccount containers: - name: bff-container image: { container_url } imagePullPolicy: Always ports: - containerPort: 3000 ---
確認
- ALB が作成されていること
- Route 53 に ALB への A レコードと TXT レコードが作成されていること