Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Kubernetes でもJava アプリでTLS 接続を終端したい
Search
Cybozu
PRO
June 16, 2024
Programming
2
340
Kubernetes でもJava アプリでTLS 接続を終端したい
2024年6月16日 (日) に開催されたJJUG CCC Spring 2024ランチセッション(6月16日 (日) 12:00 - 12:45)の発表資料です。
Cybozu
PRO
June 16, 2024
Tweet
Share
More Decks by Cybozu
See All by Cybozu
サイボウズ 開発本部採用ピッチ / Cybozu Engineer Recruit
cybozuinsideout
PRO
9
45k
テクニカルライティング
cybozuinsideout
PRO
4
300
サイボウズのアジャイルクオリティ2024
cybozuinsideout
PRO
3
260
モブに早く慣れたい人のためのガイド2024
cybozuinsideout
PRO
3
360
モバイル
cybozuinsideout
PRO
3
180
ソフトウェアライセンス
cybozuinsideout
PRO
4
160
ソフトウェアテスト
cybozuinsideout
PRO
3
260
自動テスト
cybozuinsideout
PRO
3
270
Docker入門2024
cybozuinsideout
PRO
3
450
Other Decks in Programming
See All in Programming
NSOutlineView何もわからん:( 前編 / I Don't Understand About NSOutlineView :( Pt. 1
usagimaru
0
330
Tauriでネイティブアプリを作りたい
tsucchinoko
0
370
OnlineTestConf: Test Automation Friend or Foe
maaretp
0
110
Quine, Polyglot, 良いコード
qnighy
4
640
Pinia Colada が実現するスマートな非同期処理
naokihaba
4
220
광고 소재 심사 과정에 AI를 도입하여 광고 서비스 생산성 향상시키기
kakao
PRO
0
170
C++でシェーダを書く
fadis
6
4.1k
どうして僕の作ったクラスが手続き型と言われなきゃいけないんですか
akikogoto
1
120
.NET のための通信フレームワーク MagicOnion 入門 / Introduction to MagicOnion
mayuki
1
1.5k
Better Code Design in PHP
afilina
PRO
0
120
役立つログに取り組もう
irof
28
9.6k
CSC509 Lecture 11
javiergs
PRO
0
180
Featured
See All Featured
Save Time (by Creating Custom Rails Generators)
garrettdimon
PRO
27
840
RailsConf & Balkan Ruby 2019: The Past, Present, and Future of Rails at GitHub
eileencodes
131
33k
Building Your Own Lightsaber
phodgson
103
6.1k
Scaling GitHub
holman
458
140k
What’s in a name? Adding method to the madness
productmarketing
PRO
22
3.1k
Designing Dashboards & Data Visualisations in Web Apps
destraynor
229
52k
Being A Developer After 40
akosma
86
590k
CoffeeScript is Beautiful & I Never Want to Write Plain JavaScript Again
sstephenson
159
15k
Building Flexible Design Systems
yeseniaperezcruz
327
38k
VelocityConf: Rendering Performance Case Studies
addyosmani
325
24k
The Language of Interfaces
destraynor
154
24k
The Cult of Friendly URLs
andyhume
78
6k
Transcript
Kubernetes でも Java アプリで TLS 接続を終端したい JJUG CCC 2024 Spring
#jjug_ccc_b 2024年6⽉16⽇ サイボウズ株式会社 齋藤 耕平 1
はじめまして︕ ▌齋藤 耕平 (さいとう こうへい) l サイボウズ株式会社 l 2022年中途⼊社 l
バックエンドエンジニア l グローバル向け AWS 版 kintone の開発/運⽤ ▌GitHub: github.com/sightseeker ▌Xアカウント: @SightSeekerTw 2 Tw は Twitter の 識別⽤につけてた名残り
チームワークあふれる 社会を創る サイボウズの理念は「チームワークあふれる社会を創る」こと。 私たちはその理念に沿ってチームワークを⽀えるソフトウェアを 開発し続けてきました。 サイボウズという会社
主⼒製品群 中⼩企業向けグループウェア 78,000社 中堅・⼤規模組織向けグループウェア 7,800社 業務システム構築プラットフォーム 32,000社 メール共有システム 14,200社 ※2023年11⽉末時点
4
kintone つかってますか︖ 5
あなたの近くでも “kintone” を使った業務があるかも︖ 6
私事ですが。 ▌最近⾞を乗り換えた ▌⾃動⾞の取得(購⼊)には、保管場所使⽤承諾証明書が必要 ▌⾃宅はマンションなので管理会社に発⾏を依頼する必要があった 7 乗り換え
従来の⼿続きの流れ ▌所定の⽤紙に書いて、管理会社に郵送 ▌管理会社に保管場所使⽤承諾証明書を郵送で送りかえしてもらう 8 郵送 発⾏ 郵送 リードタイム 1週間
申請, 発⾏がオンラインで完結するようになっていた ▌Webフォームに必要情報を⼊⼒して送信 ▌数時間後、承諾証明書のPDFのダウンロードURLがメールで送られてきた 9 Webフォームに申請内容を記⼊して送信 証明書をPDF 形式で発⾏ ダウンロード
1週間かかってた ⼿続きが数時間に︕ 10
11 申請フォームのURLに kintone の⽂字が !?
form.kintoneapp.com とは︖ ▌トヨクモ (株) さんの提供する FormBridge というサービスのURL︕ 12 画像出典: “トヨクモ
(株) FormBridge 製品紹介ページ https://fb.kintoneapp.com/"
kintone 最⾼︕ 13
ここからが本題 14
年々、セキュリティ要求/要件 が厳しくなってきましたね︕(雑) ▌ISMS ▌GRPR ▌PCI DSS ▌HIPAA etc… 15
最近は Java アプリ も Kubernetes に デプロイすること 多くなってきたよね︕ 16
Kubernetes クラスタ内のトラフィックを キャプチャ されても/しても ⼤丈夫なようにしときたい︕ 17
通信は暗号化 されていてほしい︕ 18
ということで、本⽇は、 19
Kubernetes でも Java アプリで TLS 接続を終端したい 20
TLS接続を終端できるようにするには何が必要か︖ 21
サーバー(TLS)証明書 22 誰のもの︖ (ドメイン名) いつまで有効︖ 発⾏者は︖ 本物︖ (発⾏者の署名)
証明書はどうやって発⾏する︖ ▌Certification Authority (CA, 認証局) に CSR (Certificate Signing Request)
を作って依頼発⾏してもらう 23
保管場所承諾証明書の話に置き換えると、こんな感じ︖ 保管場所承諾証明書 TLS 証明書 保管場所承諾書の申請書 (あるいは申請フォーム) CSR (Certificate Signing Request)
マンションの管理会社 Certification Authority (CA, 認証局) 24
パブリックドメインの証明書の認証局は︖ 25
プライベートネットワークのプライベートなドメインの認証局は︖ ▌オレオレ認証局 (独⾃に発⾏したキーペアを利⽤) ▌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
Kubernetes 内では︖ cert-manager の Issuer/ClusterIssuer を置くのが⼀般的 だと思う。 27
cert-manager とは ▌Cloud Native Computing Foundation のプロジェクトの⼀つ ▌Kubernetesクラスタ内でアプリケーション⽤の TLS 証明書の発⾏と管理を⾃動化するためのツール
(K8s の カスタムコントローラ/CRD で構成される) ▌証明書は Secret リソースとして発⾏され、 Pod にマウントして利⽤できる 28
Issuer とは ▌意味: 〔株式や本などの〕発⾏⼈[者・社] (英辞郎 on the WEB より) ▌
証明書を発⾏するための設定を定義する cert-manager のカスタムリソース ▌ 証明書を発⾏するための具体的な⽅法や 認証局(CA)の情報が含まれている ▌ ただの Issuer はデプロイされてる Namespace 内でのみ利⽤可能 ▌ ClusterIssuer は Namespace 横断で使える Issuer 29 証明書を発⾏するよ︕ Issuer さん
Issuer には多様な選択肢がある ▌⾃前で⽤意した CA ⽤のキーペアを利⽤したものや、 各種ベンダー提供の PKI, プライベート CA サービスを
Issuer として設定可能 ※各種PKI, プライベートCAサービス を Issuer として利⽤するには 別途対応するカスタムコントローラ, CRD をデプロイが必要な場合がある 30
TLS証明書を利⽤するまでの流れ ▌(cert-manager を Kubernetes にデプロイ)今回は説明を省略 ▌Issuer リソースを作成 ▌Issuer に証明書を発⾏してもらう l
Certificate リソースを作成 l Issuer が Certificate リソースに対応する証明書を発⾏ (証明書の Secret が作成される) ▌発⾏された証明書の Secret を アプリのコンテナの所定のパスにマウントして利⽤する 31
ざっくりこんな雰囲気 32 CSR が含まれるリソース
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
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) の情報
⽣成された証明書の 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
証明書の中⾝の確認 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
その証明書を使って Spring Boot アプリで TLS 接続を終端できるようにするには︖ 37 申し訳程度の Java 要素
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
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 に移⾏しつつあるよね︕
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 限定︕
これで、 Spring Boot で TLS 接続を終端できるようになったけれど クライアント的には… 41
42
クライアントが通信先はその証明書を信頼していない 43 Issuer (CA) あるいはその上位の CA の証明書を クライアント側で持っていて、信頼するものとして認識必要がある Issuer (CA)
の発⾏した証明書を信頼する必要がある
▌パブリックな CA の ルート証明書は標準でOSにバンドルされてるけれど ▌プライベートな CA の証明書は個別でインストールする必要がある 44
PEM や PKCS12 などアプリやコンテナによって必要な形式が違うし 何よりも様々なアプリのコンテナ内の 信頼するCA証明書が統⼀されてることを保証しにくい Issuer の CA証明書 がインポートされている必要があるけれど
▌コンテナイメージをビルドするときに証明書をインストールする ▌initContainer で証明書をインストールして emptyDir 経由でアプリ のコンテナに共有する 45 課題
信頼するCA証明書は ConfigMap や Secret で配布して 各Podがマウントすればよいのでは︖ 46 それでも PEM と
PKCS12 と JKS それぞれの形式で中⾝が同じ信頼するCA証明書 を同じものを作るのツラい
▌そんな悩みを解決してくれる trust-manager 47
trust-manager とは ▌cert-manager のプロジェクトで提供されている もう⼀つのカスタムコントローラと CRD のセット 48
信頼する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 証明書ファイルを
こんな 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 証明書が 各フォーマットですべて⼊っていて 中⾝が揃っている
要は、この ConfigMap は macOS でいうところの キーチェーンアクセス に登録されてる 信頼できる証明書の全量 51
あとは 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
まとめ 53
cert-manager / trust-manager 最⾼︕ ▌証明書を作るのに、クセ強めな openssl コマンドを駆使しなくていい ▌証明書の発⾏に必要な定義ファイル (Certificate のマニフェスト)
は YAML で可読性が⾼い︕ ▌プライベートでも TLS 証明書, CA 証明書の発⾏、管理、利⽤が楽︕ ▌PEM だけでなく Java でも使える JKS, PKCS12 形式もサポート︕ 54 Kubernetes でも Java アプリで TLS 接続を終端するのは難しくないよね︕
ご清聴ありがとうございました。 55
紹介しきれなかった話 ▌ 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