AKS + AGIC で TLS 終端を行う
個人的な設定方法のメモとして書き散らしておきます。
前提
- Azure Kubernetes Service (AKS) が既に構築されていること
- Application Ingress Controller (AGIC) が既に有効化されていること
- Azure Key Vault が既に構築されていること
- TLS 証明書は、自己署名証明書を使用すること
手順
初めに TLS 証明書を生成します。
$ mkdir aks-agic-tls
$ cd aks-agic-tls/
$ openssl req -x509 -nodes -days 365 -newkey rsa:2048 -out aks-ingress-tls.crt -keyout aks-ingress-tls.key -subj "/CN=demo.yuohno.com/O=aks-ingress-tls"
$ ls -l
total 8
-rw-r--r-- 1 yurio yurio 1200 Nov 28 16:45 aks-ingress-tls.crt
-rw------- 1 yurio yurio 1704 Nov 28 16:45 aks-ingress-tls.key
次に Azure Key Vault で扱う証明書は、PFX 形式である必要がある ため、PFX 形式に変換します。
また、パスワードはスキップしています。
$ openssl pkcs12 -export -in aks-ingress-tls.crt -inkey aks-ingress-tls.key -out aks-ingress-cert.pfx
Enter Export Password:
Verifying - Enter Export Password:
$ ls -l
total 12
-rw------- 1 yurio yurio 2595 Nov 28 16:46 aks-ingress-cert.pfx
-rw-r--r-- 1 yurio yurio 1200 Nov 28 16:45 aks-ingress-tls.crt
-rw------- 1 yurio yurio 1704 Nov 28 16:45 aks-ingress-tls.key
上記で生成した PFX ファイルを Azure Key Vault にアップロードします。
"キー コンテナー証明書責任者" など、証明書の操作権限を持つロールの割り当てが必要です。
$ az keyvault certificate import --vault-name $AKV_NAME --name aks-ingress-cert --file ./aks-ingress-cert.pfx
それでは Kubernete の操作に移ります。
SecretProviderClass の作成
AKS にて、Secrets Store CSI ドライバー機能を有効化すると、以下のユーザー割り当て マネージド ID が作られますので、
このクライアント ID を控えておきます。
$ kubectl create namespace ingress
$ export CERT_NAME=aks-ingress-cert
$ export AKV_NAME=<Azure Key Vault 名>
$ export TENANT_ID=<MS Entra ID テナント ID>
$ export CLIENT_ID=<ユーザー割り当て マネージド ID のクライアント ID>
$ cat << EOF | kubectl apply -n ingress -f -
apiVersion: secrets-store.csi.x-k8s.io/v1
kind: SecretProviderClass
metadata:
name: azure-tls
spec:
provider: azure
secretObjects:
- secretName: ingress-tls-csi
type: kubernetes.io/tls
data:
- objectName: $CERT_NAME
key: tls.key
- objectName: $CERT_NAME
key: tls.crt
parameters:
usePodIdentity: "false"
useVMManagedIdentity: "true"
userAssignedIdentityID: $CLIENT_ID
keyvaultName: $AKV_NAME
objects: |
array:
- |
objectName: $CERT_NAME
objectType: secret
tenantId: $TENANT_ID
EOF
それでは、この証明書を使って、アプリケーションを公開します。
ポイントとしては、上記で secrets-store-inline
の箇所で、一度 Secret としてマウントしています。
これにより、Secret が作成され、その後の Ingress から参照可能になります。
Known Limitations - Secrets Store CSI Driver
The CSI driver is invoked by kubelet only during the pod volume mount.
$ cat << EOF | kubectl apply -n ingress -f -
apiVersion: apps/v1
kind: Deployment
metadata:
name: aks-helloworld
spec:
replicas: 1
selector:
matchLabels:
app: aks-helloworld
template:
metadata:
labels:
app: aks-helloworld
spec:
containers:
- name: aks-helloworld-one
image: mcr.microsoft.com/azuredocs/aks-helloworld:v1
ports:
- containerPort: 80
env:
- name: TITLE
value: "Welcome to Azure Kubernetes Service (AKS)"
volumeMounts:
- name: secrets-store-inline
mountPath: "/mnt/secrets-store"
readOnly: true
volumes:
- name: secrets-store-inline
csi:
driver: secrets-store.csi.k8s.io
readOnly: true
volumeAttributes:
secretProviderClass: "azure-tls"
---
apiVersion: v1
kind: Service
metadata:
name: aks-helloworld
spec:
type: ClusterIP
ports:
- port: 80
selector:
app: aks-helloworld
EOF
コンテナーが稼働していることを確認して、ok ですね。
$ kubectl get deploy -n ingress
NAME READY UP-TO-DATE AVAILABLE AGE
aks-helloworld 1/1 1 1 28s
次に Ingress リソースを作成します。
$ cat << EOF | kubectl apply -n ingress -f -
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-tls
spec:
ingressClassName: azure-application-gateway
tls:
- hosts:
- demo.yuohno.com
secretName: ingress-tls-csi
rules:
- host: demo.yuohno.com
http:
paths:
- path: /
pathType: Exact
backend:
service:
name: aks-helloworld
port:
number: 80
EOF
最後に、Ingress リソースの IP アドレスを確認して、curl でアクセスしてみます。
$ kubectl get ingress -n ingress
NAME CLASS HOSTS ADDRESS PORTS AGE
ingress-tls azure-application-gateway demo.yuohno.com xxx.xxx.xxx.xxx 80, 443 10m
下記 TLS 証明書の情報が表示されており、作成した自己証明書の Common Name (CN
) および Organization Name (O
) が表示されていることを確認します。
yurio@LAPTOP-SK5100ET:~/aks-agic-tls$ curl -v -k --resolve demo.yuohno.com:443:xxx.xxx.xxx.xxx https://demo.yuohno.com
* Added demo.yuohno.com:443:xxx.xxx.xxx.xxx to DNS cache
* Hostname demo.yuohno.com was found in DNS cache
* Trying xxx.xxx.xxx.xxx :443...
* Connected to demo.yuohno.com (xxx.xxx.xxx.xxx) port 443
...(省略)...
* SSL connection using TLSv1.2 / ECDHE-RSA-AES256-GCM-SHA384 / prime256v1 / rsaEncryption
* ALPN: server accepted http/1.1
* Server certificate:
* subject: CN=demo.yuohno.com; O=aks-ingress-tls
* start date: Nov 28 07:45:49 2024 GMT
* expire date: Nov 28 07:45:49 2025 GMT
* issuer: CN=demo.yuohno.com; O=aks-ingress-tls
* SSL certificate verify result: self-signed certificate (18), continuing anyway.
* Certificate level 0: Public key type RSA (2048/112 Bits/secBits), signed using sha256WithRSAEncryption
...(省略)...
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<link rel="stylesheet" type="text/css" href="/static/default.css">
<title>Welcome to Azure Kubernetes Service (AKS)</title>
<script language="JavaScript">
function send(form){
}
</script>
</head>
<body>
<div id="container">
<form id="form" name="form" action="/"" method="post"><center>
<div id="logo">Welcome to Azure Kubernetes Service (AKS)</div>
<div id="space"></div>
<img src="/static/acs.png" als="acs logo">
<div id="form">
</div>
</div>
</body>
* Connection #0 to host demo.yuohno.com left intact
最後に Azure ポータルを開き、Application Gateway のリソースを確認して、TLS 証明書が登録されていることを確認してみます。
登録されていましたね。
ということで検証は以上です。
Discussion