Slide 1

Slide 1 text

Kubernetes でも Java アプリで TLS 接続を終端したい JJUG CCC 2024 Spring #jjug_ccc_b 2024年6⽉16⽇ サイボウズ株式会社 齋藤 耕平 1

Slide 2

Slide 2 text

はじめまして︕ ▌齋藤 耕平 (さいとう こうへい) l サイボウズ株式会社 l 2022年中途⼊社 l バックエンドエンジニア l グローバル向け AWS 版 kintone の開発/運⽤ ▌GitHub: github.com/sightseeker ▌Xアカウント: @SightSeekerTw 2 Tw は Twitter の 識別⽤につけてた名残り

Slide 3

Slide 3 text

チームワークあふれる 社会を創る サイボウズの理念は「チームワークあふれる社会を創る」こと。 私たちはその理念に沿ってチームワークを⽀えるソフトウェアを 開発し続けてきました。 サイボウズという会社

Slide 4

Slide 4 text

主⼒製品群 中⼩企業向けグループウェア 78,000社 中堅・⼤規模組織向けグループウェア 7,800社 業務システム構築プラットフォーム 32,000社 メール共有システム 14,200社 ※2023年11⽉末時点 4

Slide 5

Slide 5 text

kintone つかってますか︖ 5

Slide 6

Slide 6 text

あなたの近くでも “kintone” を使った業務があるかも︖ 6

Slide 7

Slide 7 text

私事ですが。 ▌最近⾞を乗り換えた ▌⾃動⾞の取得(購⼊)には、保管場所使⽤承諾証明書が必要 ▌⾃宅はマンションなので管理会社に発⾏を依頼する必要があった 7 乗り換え

Slide 8

Slide 8 text

従来の⼿続きの流れ ▌所定の⽤紙に書いて、管理会社に郵送 ▌管理会社に保管場所使⽤承諾証明書を郵送で送りかえしてもらう 8 郵送 発⾏ 郵送 リードタイム 1週間

Slide 9

Slide 9 text

申請, 発⾏がオンラインで完結するようになっていた ▌Webフォームに必要情報を⼊⼒して送信 ▌数時間後、承諾証明書のPDFのダウンロードURLがメールで送られてきた 9 Webフォームに申請内容を記⼊して送信 証明書をPDF 形式で発⾏ ダウンロード

Slide 10

Slide 10 text

1週間かかってた ⼿続きが数時間に︕ 10

Slide 11

Slide 11 text

11 申請フォームのURLに kintone の⽂字が !?

Slide 12

Slide 12 text

form.kintoneapp.com とは︖ ▌トヨクモ (株) さんの提供する FormBridge というサービスのURL︕ 12 画像出典: “トヨクモ (株) FormBridge 製品紹介ページ https://fb.kintoneapp.com/"

Slide 13

Slide 13 text

kintone 最⾼︕ 13

Slide 14

Slide 14 text

ここからが本題 14

Slide 15

Slide 15 text

年々、セキュリティ要求/要件 が厳しくなってきましたね︕(雑) ▌ISMS ▌GRPR ▌PCI DSS ▌HIPAA etc… 15

Slide 16

Slide 16 text

最近は Java アプリ も Kubernetes に デプロイすること 多くなってきたよね︕ 16

Slide 17

Slide 17 text

Kubernetes クラスタ内のトラフィックを キャプチャ されても/しても ⼤丈夫なようにしときたい︕ 17

Slide 18

Slide 18 text

通信は暗号化 されていてほしい︕ 18

Slide 19

Slide 19 text

ということで、本⽇は、 19

Slide 20

Slide 20 text

Kubernetes でも Java アプリで TLS 接続を終端したい 20

Slide 21

Slide 21 text

TLS接続を終端できるようにするには何が必要か︖ 21

Slide 22

Slide 22 text

サーバー(TLS)証明書 22 誰のもの︖ (ドメイン名) いつまで有効︖ 発⾏者は︖ 本物︖ (発⾏者の署名)

Slide 23

Slide 23 text

証明書はどうやって発⾏する︖ ▌Certification Authority (CA, 認証局) に CSR (Certificate Signing Request) を作って依頼発⾏してもらう 23

Slide 24

Slide 24 text

保管場所承諾証明書の話に置き換えると、こんな感じ︖ 保管場所承諾証明書 TLS 証明書 保管場所承諾書の申請書 (あるいは申請フォーム) CSR (Certificate Signing Request) マンションの管理会社 Certification Authority (CA, 認証局) 24

Slide 25

Slide 25 text

パブリックドメインの証明書の認証局は︖ 25

Slide 26

Slide 26 text

プライベートネットワークのプライベートなドメインの認証局は︖ ▌オレオレ認証局 (独⾃に発⾏したキーペアを利⽤) ▌Private PKI サービスを利⽤ l DigiCert Private PKI l Venafi Zero Touch PKI l HashiCorp Vault ▌クラウドベンダー提供のプライベートCAサービス l AWS Private Certificate Authority l Microsoft Active Directory Certificate Service l Google Cloud Certificate Authority Service 26

Slide 27

Slide 27 text

Kubernetes 内では︖ cert-manager の Issuer/ClusterIssuer を置くのが⼀般的 だと思う。 27

Slide 28

Slide 28 text

cert-manager とは ▌Cloud Native Computing Foundation のプロジェクトの⼀つ ▌Kubernetesクラスタ内でアプリケーション⽤の TLS 証明書の発⾏と管理を⾃動化するためのツール (K8s の カスタムコントローラ/CRD で構成される) ▌証明書は Secret リソースとして発⾏され、 Pod にマウントして利⽤できる 28

Slide 29

Slide 29 text

Issuer とは ▌意味: 〔株式や本などの〕発⾏⼈[者・社] (英辞郎 on the WEB より) ▌ 証明書を発⾏するための設定を定義する cert-manager のカスタムリソース ▌ 証明書を発⾏するための具体的な⽅法や 認証局(CA)の情報が含まれている ▌ ただの Issuer はデプロイされてる Namespace 内でのみ利⽤可能 ▌ ClusterIssuer は Namespace 横断で使える Issuer 29 証明書を発⾏するよ︕ Issuer さん

Slide 30

Slide 30 text

Issuer には多様な選択肢がある ▌⾃前で⽤意した CA ⽤のキーペアを利⽤したものや、 各種ベンダー提供の PKI, プライベート CA サービスを Issuer として設定可能 ※各種PKI, プライベートCAサービス を Issuer として利⽤するには 別途対応するカスタムコントローラ, CRD をデプロイが必要な場合がある 30

Slide 31

Slide 31 text

TLS証明書を利⽤するまでの流れ ▌(cert-manager を Kubernetes にデプロイ)今回は説明を省略 ▌Issuer リソースを作成 ▌Issuer に証明書を発⾏してもらう l Certificate リソースを作成 l Issuer が Certificate リソースに対応する証明書を発⾏ (証明書の Secret が作成される) ▌発⾏された証明書の Secret を アプリのコンテナの所定のパスにマウントして利⽤する 31

Slide 32

Slide 32 text

ざっくりこんな雰囲気 32 CSR が含まれるリソース

Slide 33

Slide 33 text

Issuer を作成する (1/2) ▌ openssl コマンドで CA ⽤のキーペアを作成 (Private PKI サービスなどを使わない場合) 33 # CA のプライベートキーの作成 (RSA 2048 bit) openssl genrsa -out ca.key 2048 # プライベートキーを使って CA の証明書の発⾏ openssl req -x509 -new -nodes -key ca.key ¥ -subj "/CN=sandbox" -days 3650 -out ca.crt ▌ ⽣成したキーペアの Secret を作成 # キーペアの Secret を作成 kubectl create secret tls ca-key-pair --cert=ca.crt --key=ca.key

Slide 34

Slide 34 text

Issuer に証明書を発⾏してもらう 34 ▌ Certificate リソースのマニフェストを作成 ▌ Keystore のパスワードの Secret を作成する kubectl create secret generic keystore-password ¥ --from-literal=password=changeit apiVersion: cert-manager.io/v1 kind: Certificate metadata: name: demo-cert spec: secretName: sandbox-cert-tls duration: 24h renewBefore: 12h subject: organizations: - My Organization commonName: demo dnsNames: - demo.sandbox.svc.cluster.local keystores: jks: create: true passwordSecretRef: name: keystore-password key: password issuerRef: name: sandbox-issuer kind: Issuer group: cert-manager.io kubectl apply -f demo-cert.yaml demo-cert.yaml 有効期間, 再発⾏時期 誰のものか TLS接続を終端するドメイン名 証明書のフォーマット (ここではJKSのみ定義) ※PKCS12については省略してます 発⾏者 (Issuer) の情報

Slide 35

Slide 35 text

⽣成された証明書の Secret の中⾝ 35 apiVersion: v1 type: kubernetes.io/tls kind: Secret metadata: annotations: cert-manager.io/alt-names: demo.sandbox.svc.cluster.local cert-manager.io/certificate-name: demo-cert cert-manager.io/common-name: demo cert-manager.io/ip-sans: "" cert-manager.io/issuer-group: cert-manager.io cert-manager.io/issuer-kind: Issuer cert-manager.io/issuer-name: sandbox-issuer cert-manager.io/subject-organizations: My Organization cert-manager.io/uri-sans: "" labels: controller.cert-manager.io/fao: "true" name: demo-cert-tls namespace: sandbox data: ca.crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tL (省略) keystore.jks: /u3+7QAAAAIAAAACAAAAAQAL (省略) tls.crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS (省略) tls.key: LS0tLS1CRUdJTiBSU0EgUFJJVkFURSB (省略) truststore.jks: /u3+7QAAAAIAAAABAAAAAgACY2EA (省略) truststore.p12: MIIEFgIBAzCCA+IGCSqGSIb3DQEH (省略) Certificate や Issuer に関する注釈 PEM形式の TLS 証明書キーペア (tls.crt, tls.key) PEM形式の Issuer の CA 証明書 (ca.crt) JKS形式の TLS 証明書 (keytstore.jks) JKS形式の Issuer の CA 証明書 (truststore.jks) PKCS12形式の TLS 証明書 (keystore.p12) PKCS12形式の Issuer のCA 証明書 (truststore.p12) ※Base64 Encoded

Slide 36

Slide 36 text

証明書の中⾝の確認 36 Subject: O=My Organization CN=demo Subject Alt Name: DNS:demo.sandbox.svc.cluster.local Issuer: CN=sandbox Infoaccess: undefined Validfrom: Jun 10 07:30:24 2024 GMT Validto: Jun 11 07:30:24 2024 GMT Fingerprint: 4D:BA:29:C2:9D:91:47:A7:7E:24:43:90:B0:F8:F0:9A:94:7B:56:84 Fingerprint256: A1:9F:94:E7:1A:8B:C7:9A:DF:A7:A1:C6:C9:03:E8:81:6D:E6:EF:72:6D:0D:7A:BC: 0D:02:2B:46:1A:1D:17:7B Keyusage: undefined Serialnumber: d14d6498d92f7e63ef57724579212a7a 有効期間 (Validfrom, Validto) 誰のものか (Subject) TLS接続を終端するドメイン名 (Subject Alt Name) 発⾏者 (Issuer) の情報 発⾏された証明書の識別情報 Fingerprint(256), Serialnumber

Slide 37

Slide 37 text

その証明書を使って Spring Boot アプリで TLS 接続を終端できるようにするには︖ 37 申し訳程度の Java 要素

Slide 38

Slide 38 text

Spring Boot でのマウントされた証明書の設定例 (JKS形式) 38 # サーバ証明書が⼊ってる keystore ファイルのパス spring.ssl.bundle.jks.demo.keystore.location=/path/to/cert/keystore.jks # keystore のパスワード spring.ssl.bundle.jks.demo.keystore.password=changeit # keystore の種別 (JKS) spring.ssl.bundle.jks.demo.keystore.type=JKS # keystore 内の証明書のエイリアス spring.ssl.bundle.jks.demo.key.alias=certificate # 使⽤する SSL Bundle の名前 server.ssl.bundle=demo # LISTEN ポート server.port=8443 application.properties

Slide 39

Slide 39 text

Spring Boot でのマウントされた証明書の設定例 (PKCS12形式) 39 # サーバ証明書が⼊ってる PKCS12 形式のファイルのパス spring.ssl.bundle.jks.demo.keystore.location=/path/to/cert/keystore.p12 # keystore のパスワード spring.ssl.bundle.jks.demo.keystore.password=changeit # keystore の種別 (PKCS12) spring.ssl.bundle.jks.demo.keystore.type=PKCS12 # keystore 内の証明書のエイリアス spring.ssl.bundle.jks.demo.key.alias=1 # 使⽤する SSL Bundle の名前 server.ssl.bundle=demo # LISTEN ポート server.port=8443 application.properties 最近は Java 界隈も JKS から PKCS12 に移⾏しつつあるよね︕

Slide 40

Slide 40 text

Spring Boot でのマウントされた証明書の設定例 (PEM形式) 40 # 証明書のパス spring.ssl.bundle.pem.demo.keystore.certificate=/path/to/cert/tls.crt # 証明書の秘密鍵のパス spring.ssl.bundle.pem.demo.keystore.private-key=/path/to/cert/tls.key # 使⽤する SSL Bundle の名前 server.ssl.bundle=demo # LISTEN ポート server.port=8443 application.properties Tomcat と Netty 限定︕

Slide 41

Slide 41 text

これで、 Spring Boot で TLS 接続を終端できるようになったけれど クライアント的には… 41

Slide 42

Slide 42 text

42

Slide 43

Slide 43 text

クライアントが通信先はその証明書を信頼していない 43 Issuer (CA) あるいはその上位の CA の証明書を クライアント側で持っていて、信頼するものとして認識必要がある Issuer (CA) の発⾏した証明書を信頼する必要がある

Slide 44

Slide 44 text

▌パブリックな CA の ルート証明書は標準でOSにバンドルされてるけれど ▌プライベートな CA の証明書は個別でインストールする必要がある 44

Slide 45

Slide 45 text

PEM や PKCS12 などアプリやコンテナによって必要な形式が違うし 何よりも様々なアプリのコンテナ内の 信頼するCA証明書が統⼀されてることを保証しにくい Issuer の CA証明書 がインポートされている必要があるけれど ▌コンテナイメージをビルドするときに証明書をインストールする ▌initContainer で証明書をインストールして emptyDir 経由でアプリ のコンテナに共有する 45 課題

Slide 46

Slide 46 text

信頼するCA証明書は ConfigMap や Secret で配布して 各Podがマウントすればよいのでは︖ 46 それでも PEM と PKCS12 と JKS それぞれの形式で中⾝が同じ信頼するCA証明書 を同じものを作るのツラい

Slide 47

Slide 47 text

▌そんな悩みを解決してくれる trust-manager 47

Slide 48

Slide 48 text

trust-manager とは ▌cert-manager のプロジェクトで提供されている もう⼀つのカスタムコントローラと CRD のセット 48

Slide 49

Slide 49 text

信頼するCA証明書の設定 (Bundle) 49 apiVersion: trust.cert-manager.io/v1alpha1 kind: Bundle metadata: name: mybundle spec: sources: - useDefaultCAs: true - secret: name: ca-cert-secret key: ca.crt target: configMap: key: "ca-certificates.crt" additionalFormats: jks: key: "bundle.jks" pkcs12: key: "bundle.p12" namespaceSelector: matchLabels: sandbox: "true" パブリックな CA のルート証明書など useDefaultCAs -> Debian コンテナにデフォで⼊ってるやつ Issuer の CA 証明書 の Secret (Secret 以外にも In-line で PEMの内容を書いたりもできる) 発⾏する証明書のフォーマット (configMap, additinalFormats) ※keystoreのパスワード設定は省略してます 信頼するCA証明書のConfigMapを配布先 Namespace の指定 合成した CA 証明書ファイルを

Slide 50

Slide 50 text

こんな ConfigMap を作ってくれる 50 apiVersion: v1 binaryData: bundle.jks: /u3+7QAAAAIAAACCAAAAAgCkMDJlZDBlYjJ8Y249ZW50cnVzd (省略) bundle.p12: MIMCtEUCAQMwgwK0PQYJKoZIhvcNAQcBoIMCtC0EgwK0KDCD (省略) data: ca-certificates.crt: | -----BEGIN CERTIFICATE----- MIIH0zCCBbugAwIBAgIIXsO3pkN/pOAwDQYJKoZIhvcNAQEFBQAwQjESMBAGA1UE (省略) -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFgzCCA2ugAwIBAgIPXZONMGc2yAYdGsdUhGkHMA0GCSqGSIb3DQEBCwUAMDsx (省略) ----END CERTIFICATE----- . . . kind: ConfigMap metadata: annotations: trust.cert-manager.io/hash: (省略) labels: trust.cert-manager.io/bundle: mybundle name: mybundle JKS 形式の CA 証明書 PKCS12 形式の CA 証明書 PEM 形式の CA 証明書 信頼できる CA 証明書が 各フォーマットですべて⼊っていて 中⾝が揃っている

Slide 51

Slide 51 text

要は、この ConfigMap は macOS でいうところの キーチェーンアクセス に登録されてる 信頼できる証明書の全量 51

Slide 52

Slide 52 text

あとは Pod にマウントして使うだけ ▌PEM形式は適切なパスにマウントするのが良さそう (Linux はディストリビューションによってパスが異なる) 52 /etc/ssl/certs/ca-certificates.crt // Debian/Ubuntu/Gentoo etc. /etc/pki/tls/certs/ca-bundle.crt // Fedora/RHEL 6 /etc/ssl/ca-bundle.pem // OpenSUSE /etc/pki/tls/cacert.pem // OpenELEC /etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem // CentOS/RHEL 7 /etc/ssl/cert.pem // Alpine Linux ▌Java で使いたい場合は適当なところに置いてオプションで指定が良さそう︖ java –Djavax.net.ssl.trustStore=/app/resources/bundle.p12 ¥ -Djavax.net.ssl.trustStorePassword=changeit ¥ -Djavax.net.ssl.trustStoreType=PKCS12 -jar /app/app.jar

Slide 53

Slide 53 text

まとめ 53

Slide 54

Slide 54 text

cert-manager / trust-manager 最⾼︕ ▌証明書を作るのに、クセ強めな openssl コマンドを駆使しなくていい ▌証明書の発⾏に必要な定義ファイル (Certificate のマニフェスト) は YAML で可読性が⾼い︕ ▌プライベートでも TLS 証明書, CA 証明書の発⾏、管理、利⽤が楽︕ ▌PEM だけでなく Java でも使える JKS, PKCS12 形式もサポート︕ 54 Kubernetes でも Java アプリで TLS 接続を終端するのは難しくないよね︕

Slide 55

Slide 55 text

ご清聴ありがとうございました。 55

Slide 56

Slide 56 text

紹介しきれなかった話 ▌ cert-manager / trust-manager のインストール⽅法 (helmで簡単に⼊れられるよ︕) ▌ 証明書のローテーション l cert-manager は Certificate に有効期間を定義できて、 ⾃動的に対応する証明書の Secret をローテーションしてくれる l Secret の値が更新されても、Pod にマウントされてる証明書は更新されないので、Pod の置き換えが必要 l Secret や ConfigMap の更新をトリガーに rollout restart してくれるコントローラ “wave-k8s/wave” とかを⼊れておくのが良さそう (Deployment や StatefulSet, DaemonSet リソースの annotation で対象を識別する) ▌ 1枚の TLS 証明書 の Secret を複数の replicas Pod で使い回すのどうなの︖ っていう気持ちにも対応できる 公式 CSI Driver もあるよ ▌ Issuer (CA) の階層化, 証明書発⾏の承認プロセス, 証明書のRBAC ▌ Replicas Pod 間の通信で IP SANs を使いたいとき 56