メインコンテンツへスキップ
見出し画像

aws-privateca-issuer使ってみた


    エンジニア4年目になりました、中島です。

    今回aws-privateca-issuerについて調べる機会がありましたので、備忘録もかねて記事を書きました。
    拙い内容ですが、お付き合いいただけると幸いです。


    aws-private-issuerって?

    まず前提として、Kubernetes内で使用するtls通信用の証明書を管理するコンポーネントとして、cert-managerというものが存在します。

    aws-privateca-issuerは、そのcert-managerにおいて
    aws-private-caサービスをCAとして使う際に証明書リクエストをやってくれる拡張機能です。
    証明書はsecretとして保存されて各Pod, Ingressによって参照されるため、証明書の定期更新を完全に自動化できます。


    やること

    前提:Kubernetes v1.34

    画像

    Nginx PodとIngress作る

    本筋じゃないのでざっくりと。

    Ingres Controllerインストール
    今回nginx

    kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.14.1/deploy/static/provider/cloud/deploy.yam


    nginxが動くPodを作成

    apiVersion: v1
    kind: Pod
    metadata:
      name: test-web
      labels:
        app: test-web
    spec:
      containers:
      - name: nginx
        image: nginx:1.14.2
        ports:
        - containerPort: 80


    Service(ClusterIP)を作成して内部Networkで公開

    apiVersion: v1
    kind: Service
    metadata:
      name: test-service
    spec:
      type: NodePort
      selector:
        app: test-web
      ports:
      - protocol: TCP
        port: 80
        targetPort: 80


    リクエストをServiceへ転送するIngress作成

    apiVersion: networking.k8s.io/v1
    kind: Ingress
    metadata:
      name: test-ingress
      annotations:
        nginx.ingress.kubernetes.io/rewrite-target: /
    spec:
      ingressClassName: nginx
      tls:
      - hosts:
        - example.local
      rules:
      - host: example.local
        http:
          paths:
          - path: /top_page
            pathType: Prefix
            backend:
              service:
                name: test-service
                port:
                  number: 80


    外部からアクセスするためのIP,Portを確認

    $ kubectl get service -n ingress-nginx
    画像
    https://<NodeのIP>: 30238 でアクセス可能だと分かります。

    TLSを使用する都合、URLにIPアドレスべた書きだと都合が悪いため、ClientPCのhostsファイル(windowsの場合C:\Windows\System32\drivers\etc\hosts)を編集して適当な名前(example.local)を付けてあげます。

    <IPアドレス> example.local


    これでアクセス可能に!

    画像
    デフォルトだとIngressがフェイクの証明書を提示するため、警告が出ます。

    Cert-managerセッティング

    Helmでcert-managerインストール

    helm install \
      cert-manager oci://quay.io/jetstack/charts/cert-manager \
      --version v1.19.2 \
      --namespace cert-manager \
      --create-namespace \
      --set crds.enabled=true

    これでcert-manager名前空間にPodが立ち
    Certificate, Certificaterequestsといったカスタムリソースも使えるようになります。

    AWS Private CAをセッティング

    そのアカウントで最初に作成したPrivate CAに限り、30日間のトライアル期間が存在する模様。ただし証明書発行するたびの課金は発生するようです。
    (詳細はこちら)

    画像

    適当な情報を入れて作成。ARNを控えておきます。
    また、ActionsボタンからCA証明書をダウンロードできるため、Client PCのブラウザにImportしておきます。

    画像

    aws-privateca-issuerが使う認証情報をセッティング

    ※最近はIAM Anywhereを使った、secret_keyをトラフィックに流さない方式が推奨されているようです。今回は構成を分かりやすくするため、IAMユーザを作ってACCESS KEYをissuerに渡す方式を使います。AWS anywhereは、、そのうち記事にするかも…


    IAMポリシー作成

    以下が最小権限のようです。適当な名前で保存しましょう。

    {
      "Version": "2012-10-17",
      "Statement": [
        {
          "Sid": "awspcaissuer",
          "Action": [
            "acm-pca:DescribeCertificateAuthority",
            "acm-pca:GetCertificate",
            "acm-pca:IssueCertificate"
          ],
          "Effect": "Allow",
          "Resource": "<作成したprivate caのARN>"
        }
      ]
    }

    IAMユーザ作成

    先ほど作成したIAMポリシーを直接アタッチして適当なユーザを作成
    →アクセスキーを作成し、IDとSECRETを控えます。
    ※当然非推奨。本番環境では避けましょう。


    aws-privateca-issuerのインストール

    helmでaws-private-issuerをインストール

    helm repo add awspca https://cert-manager.github.io/aws-privateca-issuer
    helm install awspca/aws-privateca-issuer --generate-name

    これでdefault名前空間にaws-privateca-issuerのPodが立ちます。

    Secret作成

    IssuerがprivatecaにアクセスするためのSECRET

    apiVersion: v1
    kind: Secret
    metadata:
      name: pca-secret
      namespace: default
    data:
      AWS_ACCESS_KEY_ID: <base64_encoded_access_key_id> 
      AWS_SECRET_ACCESS_KEY: <base64_encoded_secret_access_key>

    ※base64エンコードする際は以下コマンドを使います。
     私は -n オプションを忘れたせいで半日溶けました。

    $ echo -n "<encodeしたい文字列>" |base64


    Secretを参照するAWSPCAIssuerカスタムリソースを作成

    apiVersion: awspca.cert-manager.io/v1beta1
    kind: AWSPCAIssuer
    metadata:
      name: pca-issuer-rsa
      namespace: default
    spec:
      arn: "<aws private caのARN>"
      region: <region>
      secretRef:
        namespace: default
        name: pca-secret

    AWSPCAIssuerとAWSPCAClusterIssuerの違いは、その名前空間のリソースかグローバルなリソースかというだけなので、どちらでもOKです。

    Describeして認証が通っていることを確認

    $ kubectl describe awspcaissuer
    画像

    証明書を発行する

    証明書を発行するには、Certificateというカスタムリソースを作成し、そこでCSRに必要な情報を定義します。
    以下、最小構成。

    kind: Certificate
    apiVersion: cert-manager.io/v1
    metadata:
      name: test-cert
      namespace: default
    spec:
      #なんでもOK
      commonName: Nara
      #httpsアクセス時のurlのホスト名と照合するため、クライアントのhostsファイルに記載したホスト名
      dnsNames:
        - example.local
      #有効期限
      duration: 72h0m0s
      issuerRef:
        group: awspca.cert-manager.io
        kind: AWSPCAIssuer
        name: pca-issuer-rsa
      #有効期限が切れるどれくらい前に証明書を再発行するか
      renewBefore: 24h0m0s
      #証明書のoutput先のsecret名
      secretName: tls-test-secret
      usages:
        - server auth
       #AWS Private CA側で定義したアルゴリズムを指定
      privateKey:
        algorithm: "RSA"
        size: 2048

    READYがTrueになっていれば大丈夫です!

    $ kubectl get certificate
    画像

    そしてサーバ証明書入りのsecretが作られているはず…

    $ kubectl get secret tls-test-secret
    画像
    無事、作成されていました!

    トラブルシューティング

    上手くいかないときのチェック項目は以下です。

    ・Aws-private-issuer Podのログ
     AWSとの疎通の過程で問題があれば、大体こちらにエラーを吐きます。

    $ kubectl logs <Pod名>


    ・CSRに問題がある場合
     certificaterequest リソースのeventに何か書いてあるかも…

    $ kubectl describe certificaterequest

    ・Certificateオブジェクトのevent
     こちらも一応確認します。

    $ kubectl describe certificate


    Ingressにサーバ証明書を読み込ませる

    Spec.tls.hosts[].secretNameに参照先のSecretを入れるだけです。
    サーバ証明書はIngressが読み込める形式で出力されているため、一発でした。

    apiVersion: networking.k8s.io/v1
    kind: Ingress
    metadata:
      name: test-ingress
      annotations:
        nginx.ingress.kubernetes.io/rewrite-target: /
    spec:
      ingressClassName: nginx
      tls:
      - hosts:
        - example.local
        secretName: tls-test-secret
      rules:
      - host: example.local
        http:
          paths:
          - path: /top_page
            pathType: Prefix
            backend:
              service:
                name: test-service
                port:
                  number: 80

    何故かエラー出てるけど、証明書の検証は成功してくれました…
    エラー出てるけど。

    画像

    FireFoxだとちゃんとHTTPS通信してくれました。何故でしょうか…

    画像

    クリーニング

    クリーニング対象は以下です。
    特にAWS Private CAは高価なので、早急に削除しましょう!

    • 作成したAWS Private CA

    • 作成したIAM ポリシー

    • 作成したIAMユーザとアクセスキー

    • Kubernetesのリソース(作成した際と逆の順番でクリーニング)

    あとがき

    cert-managerの挙動含め、良い勉強になりました。
    簡単に証明書周りを管理できてとっても便利だね、といった感想です。
    以上、ご一読いただきありがとうございました。


    参照情報

    参考にしたAWSドキュメント

    cert-manager

    AWS Private CA Issuer



    LINKI’N FELLOWSではともに働く仲間を探しています


    生成AI、E資格学習なら  Human-centric AI Lab

    最新情報は公式Xにて配信しています

    初noteを公開しました!

    これまで他媒体にて掲載していた記事を含め、会社関連情報を順次noteにて公開していきます。

    記念すべき初回は会社設立20周年記念パーティの様子をお届けします。https://t.co/GNHFLdEnof

    — 株式会社 LINKI’N FELLOWS (@LINKINFELLOWS) October 16, 2025

    弊社の「E資格講座」を修了した2名のうち2名が
    「E資格 2024 #2」試験に合格しました!
    なんと、合格率100%です!

    皆さまのご参加お待ちしております!

    弊社「E資格講座」はこちらhttps://t.co/zCA2JZsIzW

    「E資格 2024 #2」合格発表ページhttps://t.co/5LaRFvVpls#E資格

    — HumanCentricAILab (@HCAI_Lab) March 26, 2025


    あなたへのおすすめ