弊サークルでは Kubernetes を microk8s で運用していました。
しかし、拡張性が足りない という致命的な欠点を持ち合わせていました。
Kubernetes の再構築
Kubeadm であれば、拡張しやすいということを知り、Kubernetes を一から組み直してみました。
下記が構成図になります。
kube-apiserver の冗長化 (HAProxy + keepalived)
Kubernetes のコントロールプレーンでは kube-apiserver が単一障害点になりがち。今回は HAProxy と keepalived を組み合わせて冗長化してる。
- HAProxy: L4 ロードバランサとして API サーバー群の TCP/6443 を振り分ける。ヘルスチェックで死活を監視して、疎通できないコントロールプレーンを自動で切り離す。
- keepalived: VIP(仮想 IP)を管理してフェイルオーバーを実現。Control plane ノードまたは専用 LB ノードで VRRP による VIP 切替を行う。
設計ポイント:
- VIP をクライアント(kubectl / kubelets / 他クラスター連携)に公開して、どのコントロールプレーンが生きていても同じエンドポイントで API を叩けるようにする。
- HAProxy 側でバックエンドの
kube-apiserverに対して定期的にヘルスチェックを行い、応答しないノードは外す。 - etcd の冗長化(クラスタ化)と合わせて設計すること。API の冗長化だけでは状態の整合が保てない場合がある。
Cilium — IPv6 (L2) を有効化
Cilium が IPv6 の L2 モードを正式にサポートしたので、今回はクラスタネットワークに Cilium を採用。IPv6 ネイティブ環境や将来のアドレス枯渇対応を見据えての選択。
ポイント:
- Cilium の IPv6 L2 モードでは、Pod ネットワークを IPv6 でネイティブに通信させつつ L2 ライクな振る舞いが可能。
- kube-proxy 置き換え(eBPF ベース)や NetworkPolicy のパフォーマンス改善が期待できる。
- デプロイ時に IPv6 を有効化し、クラスタ全体を single-stack IPv6 または dual-stack に合わせて設定する必要あり。クラウド環境やオンプレのネットワーク設定(RA, SLAAC, ルーティング)にも注意。
導入時の注意:
- CNI 設定で IPv6 を ON にすること、ノードのカーネルやカーネルパラメータが eBPF/IPv6 に対応していることを確認する。
- 他のコンポーネント(Ingress / ServiceLB / ExternalDNS 等)の IPv6 対応状況をチェックする。
詳しくは、こちらの記事にまとめています。
Traefik を Ingress に採用
外部公開には Traefik を採用。Kubernetes の Ingress を受けて HTTP/HTTPS をさばく役回り。
メリット:
- 動的設定反映が速く、CRD(IngressRoute)や middleware を使った柔軟なルーティングが書ける。
- Let's Encrypt / cert-manager と組み合わせて TLS を自動更新できる。
- ダッシュボードや Prometheus メトリクス連携が簡単で、可観測性も良い。
運用メモ:
- Traefik をクラスタ内の Deployment として動かすか、外部のロードバランサの背後で動かすかは要件次第。今回は Traefik をクラスタ内で動かし、Cilium で 80/443 を振る構成にしてる。
Istio で mTLS を導入
サービス間通信のセキュリティには Istio を導入して mTLS を有効化。サービスメッシュで暗号化とポリシーベースの制御を実現してる。
基本方針:
- Istio の
PeerAuthenticationを使って mTLS をSTRICTにすると、メッシュ内通信は自動的に相互 TLS で保護される。 - サービスごとに
DestinationRule/Policy(バージョンにより API 名は変わる)で細かい許可・拒否を設定。
例: 全メッシュに対して厳密な mTLS を有効にする簡単な PeerAuthentication:
apiVersion: security.istio.io/v1beta1
kind: PeerAuthentication
metadata:
name: default
namespace: istio-system
spec:
mtls:
mode: STRICT
運用上の注意:
- mTLS 適用前に、サイドカー注入や互換性のあるバージョンで段階的に有効化していくこと。
Capsule を使ったマルチテナントと OIDC 認証
今回の構成では、サークルの基盤システム(OIDC プロバイダとして UniQUE を運用)と、Capsule によるマルチテナントなテナント環境の 2 層構成にしています。要点はこんな感じです。
- 区分け: 基盤側は共通サービス(CI/CD、監視、認証:UniQUE 等)をホスト。テナント環境は Capsule で隔離された Namespace 単位の環境を提供して、各テナントにリソースやポリシーを割り当てる。
- 認証: テナント側は OIDC で認証する設計。UniQUE を OIDC プロバイダにして、ユーザーやサービスは UniQUE 経由でログイン/トークン取得を行い、Kubernetes API やクラスタ内アプリにアクセスする。
- Capsule の利点: Namespace レベルでのテナント分離、Quota/Limit、NetworkPolicy や RBAC のテンプレート化、そして管理者がテナント毎のコントロールを維持できる点が強み。
- RBAC と OIDC の連携: OIDC の Claim(group, email など)を使って Kubernetes の RoleBinding/ClusterRoleBinding を発行することで、テナントごと/グループごとの権限付与が可能。
運用メモ:
- テナントのセルフサービスを提供する場合、UniQUE 側でクライアント登録やスコープ設計をきちんと定義しておくとスムーズ。
- 外部からの ID トークンで kube-apiserver にアクセスさせる際は、API サーバーの
--authentication-token-webhook-config-fileや OIDC 認証設定を適切に組むこと。 - ネットワーク分離やリソース制限は Capsule のテンプレを活用して自動化すると運用コスト下げられる。
これでテナント毎にセキュアで独立した環境を提供しつつ、サークル共通の認証基盤(UniQUE)で統一されたアクセス制御ができるようにしています。
- 外部サービスやメッシュ外からのトラフィックを受ける場合は Gateway / ingress の TLS 設定を別途用意する。
HashiCorp Vault を使ったシークレット管理
シークレット管理には HashiCorp Vault を採用しており、Kubernetes と連携してクラスター内のシークレット配布・アクセス制御を行っています。Vault を導入することで、機密情報の漏洩リスク低減、きめ細かいポリシー管理、監査ログの取得が容易になります。
主な導入パターン:
- Vault サーバーを HA 構成で用意し、ストレージバックエンド(Consul や Cloud KVS 等)で永続化する
- Kubernetes 向けには
kubernetes authを有効化して ServiceAccount ベースで認証する - シークレットの配布は以下のいずれかを採用するのが現実的
- Vault CSI Provider(Secrets Store CSI Driver + Vault プロバイダ)で Pod にマウント
- Vault Agent Injector で Pod 起動時に環境変数やファイルに注入
- アプリ側で Vault API を直接叩く(より自由度は高いが実装コストが必要)
簡単な導入手順(概要):
- Vault を HA でデプロイし、バックエンドストレージを設定する(例: Consul)
-
kubernetes認証を有効化し、Vault 側で Role を作成して Kubernetes の ServiceAccount と紐付ける
例(Vault 側の概略コマンド):
# kubernetes auth を有効化
vault auth enable kubernetes
# Kubernetes API と連携するための設定(token_reviewer_jwt, kubernetes_host 等を指定)
vault write auth/kubernetes/config \
token_reviewer_jwt="$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)" \
kubernetes_host="https://$KUBERNETES_HOST" \
kubernetes_ca_cert=@/var/run/secrets/kubernetes.io/serviceaccount/ca.crt
# Role を作成して ServiceAccount を束ねる
vault write auth/kubernetes/role/my-role \
bound_service_account_names=vault-sa \
bound_service_account_namespaces=default \
policies=my-policy \
ttl=24h
- Kubernetes 側で ServiceAccount を作成し、Pod に Vault CSI や Vault Agent を組み込む
例(SecretProviderClass の概略):
apiVersion: secrets-store.csi.x-k8s.io/v1
kind: SecretProviderClass
metadata:
name: vault-secret
spec:
provider: vault
parameters:
vaultAddress: "https://vault.example.com"
roleName: "my-role"
objects: |
- objectName: "secret/data/myapp/config"
secretPath: "secret/data/myapp/config"
type: "kv"
運用上の注意点:
- Vault のアンシールとバックアップ運用を自動化する(Auto Unseal を使うと楽)
- Vault のポリシーは最小権限原則に従って設計する
- シークレットのローテーションと監査ログの運用ルールを決める
- CSI/Injector のどちらを使うかはアプリの要件(ファイルマウントが良いか、環境変数での注入が良いか)で選定する
Istio / Capsule との連携:
- Vault で発行する証明書を使って mTLS の証明書管理を行ったり、テナント単位でポリシーを分離する運用も可能です。Capsule によるテナント分離下でも、各テナント用の Vault ポリシーや Role を用意することで管理できます。(そんな境地には達していない)
これにより、シークレット管理がセキュアかつ運用しやすくなり、認証基盤(UniQUE)やサービスメッシュと組み合わせた一貫したセキュリティ設計が実現できます。
最後に
メンバーの個人情報を扱う UniQUE を運用し始めるにあたって、セキュリティ面も気にするようになり、さまざまなコンポーネントを追加して拡張することになりました。
誰かの設計の参考になれば幸いです。
また、当サークルでは ProxmoxVE や Kubernetes を運用しています。
もし興味がありましたら、下記 URL へ飛んでいただければと思います!
⭐︎ 公式 HP ↓
⭐︎ Discord ↓
