Azure DNSとcert-managerを用いたLet's Encryptのワイルドカード証明書の発行と利用
Azure Kubernetes Service(AKS)とLet's Encryptを使ったワイルドカードTLS証明書の設定に苦労したのでメモをシェアしたいと思います。
この記事が同じ課題に直面している方々の助けとなれば幸いです。
ワイルドカードを使わない場合は、HTTP-01チャレンジを使用して証明書を発行できます。その手順は、Azureの公式ドキュメントに記載されているので、そちらを参照してください。
AKSクラスタを作成
まず始めに、Terraformを使用してAKSクラスタを作成します。
ここで特筆すべき重要な点は、サービスプリンシパルをDNSゾーンのコントリビューターとして追加することです。
resource "azurerm_resource_group" "example" {
name = "example-resources"
location = "japaneast"
}
resource "azuread_application" "example" {
name = "example"
}
resource "azuread_service_principal" "example" {
application_id = azuread_application.example.application_id
}
resource "azuread_service_principal_password" "example" {
service_principal_id = azuread_service_principal.example.id
end_date = "2099-01-01T01:02:03Z"
}
resource "azurerm_kubernetes_cluster" "example" {
name = "example-aks1"
location = azurerm_resource_group.example.location
resource_group_name = azurerm_resource_group.example.name
dns_prefix = "exampleaks1"
default_node_pool {
name = "default"
node_count = 2
vm_size = "Standard_D2_v2"
}
identity {
type = "SystemAssigned"
}
}
resource "azurerm_dns_zone" "example" {
# DNSゾーンを指定
name = "example.com"
resource_group_name = azurerm_resource_group.example.name
}
# ※重要
resource "azurerm_role_assignment" "role_assignment" {
scope = azurerm_dns_zone.example.id
role_definition_name = "DNS Zone Contributor"
principal_id = azuread_service_principal.example.id
}
data "azurerm_client_config" "config" {}
output "service_principal_info" {
value = {
client_id = azuread_application.example.application_id
tenant_id = data.azurerm_client_config.config.tenant_id
password = azuread_service_principal_password.example.value
}
description = "The Service Principal information"
sensitive = true
}
Terraformの適用が完了した後、以下のコマンドを実行してサービスプリンシパルの情報を出力します。この情報は後のステップで必要になります。
terraform output service_principal_info
cert-managerをインストール
kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.12.2/cert-manager.yaml
Azure DNS用のDNS-01チャレンジの設定
証明書を利用するnamespaceを用意(オプショナル)
まず、環境変数を設定します。以下のコマンドは、BashやZshなどのPOSIX互換シェルで動作します。もし異なるシェル(Fishなど)を使用している場合は、そのシェルの文法に従って環境変数を設定してください。
また、namespaceはdefault
でも構いませんが、後続のコマンドで$NAMESPACE
が参照されるので注意してください。
export NAMESPACE=demo
次に、上で設定した$NAMESPACE
を使ってKubernetesのnamespaceを作成します。
kubectl create namespace $NAMESPACE
サービスプリンシパルのパスワードを含んだSecretを用意
terraform output
で出力したパスワードをbase64エンコードします。
echo <the-password> | openssl base64
上記で出力したパスワードを使用してSecret
を作成します。
ここで注意点として、namespaceをcert-manager
に設定することが重要です。
apiVersion: v1
kind: Secret
metadata:
name: secret-azuredns-config
namespace: cert-manager
data:
password: <the-password-in-base64>
適用します。
kubectl apply -f secret.yaml
ドメインの所有を証明する設定を用意
以下を埋めて2つのファイル(ClusterIssuer
とCertificate
)を作成します。
<your-email>
<service-principal-client-id>
<your-subscription-id>
<your-resource-group>
<your-dns-zone-name>
<your-tenant-id>
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt
spec:
acme:
server: https://acme-v02.api.letsencrypt.org/directory
email: <your-email>
privateKeySecretRef:
name: letsencrypt
solvers:
- dns01:
azureDNS:
clientID: <service-principal-client-id>
clientSecretSecretRef:
name: secret-azuredns-config
key: password
subscriptionID: <your-subscription-id>
resourceGroupName: <your-resource-group>
hostedZoneName: <your-dns-zone-name>
tenantID: <your-tenant-id>
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: wildcard
spec:
# 指定した名前でSecretが作成される
secretName: wildcard
issuerRef:
name: letsencrypt
kind: ClusterIssuer
dnsNames:
- "*.<your-domain>"
usages:
- server auth
適用します。
kubectl apply -f cluster-issuer.yaml --namespace $NAMESPACE
kubectl apply -f certificate.yaml --namespace $NAMESPACE
証明書オブジェクトが作成されたことを確認
ここまでの手順が完了すると、Azure DNSゾーンにTXTレコードが一時的に作成され証明書が発行されます。タイミングが合えば以下のようなレコードが作成されていることが確認できます。
以下のREADY
がTrue
になっていれば証明書の発行が完了しているはずです。
kubectl get certificate --namespace $NAMESPACE
NAME READY SECRET AGE
wildcard True wildcard 5m1s
TLSの Secret
が作成されていることも確認します。
kubectl get secret --namespace $NAMESPACE
NAME TYPE DATA AGE
wildcard kubernetes.io/tls 2 5m13s
証明書を利用する
最後にNGINX Ingress Controller
で証明書を利用するサンプルを紹介します。
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: nginx-ingress
annotations:
nginx.ingress.kubernetes.io/ssl-redirect: "true"
spec:
ingressClassName: nginx
tls:
- hosts:
- "*.<your-domain>"
secretName: wildcard
rules:
- host: "*.<your-domain>"
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: nginx-default
port:
number: 80
以上で終了になります。それではみなさん良いAzureライフを!
Discussion