SPIRE

SPIREは、異種環境で実行されているワークロードに暗号化されたIDを安全に発行するために、ノードとワークロードの証明を実行する、SPIFFE仕様のプロダクション対応実装です。 SPIREは、EnvoyのSDS APIとの統合を通じて、Istioワークロードの暗号化IDのソースとして構成できます。 Istioは、定義されたソケットパスでEnvoy SDS APIを実装するUNIXドメインソケットの存在を検出できるため、Envoyはそれと直接通信してIDをフェッチできます。

このSPIREとの統合により、Istioの強力なサービス管理を活用しながら、デフォルトのIstioのID管理では利用できない柔軟な証明オプションが提供されます。例えば、SPIREのプラグインアーキテクチャにより、Istioが提供するKubernetes名前空間やサービスアカウントの証明を超えた、多様なワークロード証明オプションが可能になります。SPIREのノード証明は、ワークロードが実行される物理または仮想ハードウェアにまで証明を拡張します。

このSPIREとIstioの統合がどのように機能するかの簡単なデモについては、EnvoyのSDS APIを介してSPIREをCAとして統合するをご覧ください。

SPIREのインストール

SPIREのインストール、および本番環境へのSPIREのデプロイについては、SPIREのインストール手順とベストプラクティスに従うことをお勧めします。

このガイドの例では、SPIREとIstioを統合するために必要な設定のみに焦点を当てるため、SPIRE Helmチャートをアップストリームのデフォルト設定で使用します。

$ helm upgrade --install -n spire-server spire-crds spire-crds --repo https://spiffe.github.io/helm-charts-hardened/ --create-namespace
$ helm upgrade --install -n spire-server spire spire --repo https://spiffe.github.io/helm-charts-hardened/ --wait --set global.spire.trustDomain="example.org"

デフォルトでは、上記に加えて以下もインストールされます。

  • SPIFFE CSIドライバー。これは、Envoy互換のSDSソケットをプロキシにマウントするために使用されます。hostMountsはセキュリティリスクが大きく、運用上のハードルも発生するため、SDSソケットをマウントするためにSPIFFE CSIドライバーを使用することをIstioとSPIREの両方が強く推奨しています。このガイドでは、SPIFFE CSIドライバーの使用を前提としています。

  • SPIRE Controller Manager。これにより、ワークロードのSPIFFE登録の作成が容易になります。

ワークロードの登録

設計上、SPIREは、SPIREサーバーに登録されたワークロードにのみIDを付与します。これには、ユーザーワークロードだけでなく、Istioコンポーネントも含まれます。SPIRE統合用に設定されたIstioサイドカーとゲートウェイは、事前に作成された既存の一致するSPIRE登録がない限り、IDを取得できず、したがってREADYステータスに到達できません。

複数のセレクターを使用して証明基準を強化する方法、および利用可能なセレクターの詳細については、ワークロードを登録するためのSPIREドキュメントを参照してください。

このセクションでは、SPIREサーバーにIstioワークロードを登録するために利用できるオプションについて説明し、いくつかのワークロード登録の例を示します。

オプション1:SPIREコントローラーマネージャーを使用した自動登録

新しいエントリは、ClusterSPIFFEIDカスタムリソースで定義されたセレクターに一致する新しいポッドごとに自動的に登録されます。

IstioサイドカーとIstioゲートウェイの両方をSPIREに登録して、IDを要求できるようにする必要があります。

Istioゲートウェイ ClusterSPIFFEID

以下では、istio-system名前空間にスケジュールされ、istio-ingressgateway-service-accountという名前のサービスアカウントを持つIstio IngressゲートウェイポッドをSPIREに自動登録するClusterSPIFFEIDを作成します。これらのセレクターは簡単な例として使用されています。SPIRE Controller Managerのドキュメントで詳細を確認してください。

$ kubectl apply -f - <<EOF
apiVersion: spire.spiffe.io/v1alpha1
kind: ClusterSPIFFEID
metadata:
  name: istio-ingressgateway-reg
spec:
  spiffeIDTemplate: "spiffe://{{ .TrustDomain }}/ns/{{ .PodMeta.Namespace }}/sa/{{ .PodSpec.ServiceAccountName }}"
  workloadSelectorTemplates:
    - "k8s:ns:istio-system"
    - "k8s:sa:istio-ingressgateway-service-account"
EOF

Istioサイドカー ClusterSPIFFEID

以下では、spiffe.io/spire-managed-identity: trueラベルを持つポッドで、default名前空間にデプロイされたものをSPIREに自動登録するClusterSPIFFEIDを作成します。これらのセレクターは簡単な例として使用されています。SPIRE Controller Managerのドキュメントで詳細を確認してください。

$ kubectl apply -f - <<EOF
apiVersion: spire.spiffe.io/v1alpha1
kind: ClusterSPIFFEID
metadata:
  name: istio-sidecar-reg
spec:
  spiffeIDTemplate: "spiffe://{{ .TrustDomain }}/ns/{{ .PodMeta.Namespace }}/sa/{{ .PodSpec.ServiceAccountName }}"
  podSelector:
    matchLabels:
      spiffe.io/spire-managed-identity: "true"
  workloadSelectorTemplates:
    - "k8s:ns:default"
EOF

オプション2:手動登録

推奨オプションで言及されているSPIRE Controller Managerを使用するのではなく、SPIRE登録を手動で作成する場合は、手動登録に関するSPIREドキュメントを参照してください。

以下は、オプション1の自動登録に基づいた、同等の手動登録です。以下の手順では、SPIREエージェントとノード証明を手動で登録するためのSPIREドキュメントにすでに従っていること、およびSPIREエージェントがSPIFFE ID spiffe://example.org/ns/spire/sa/spire-agentで登録されていることを前提としています。

  1. spire-serverポッドを取得します。

    $ SPIRE_SERVER_POD=$(kubectl get pod -l statefulset.kubernetes.io/pod-name=spire-server-0 -n spire-server -o jsonpath="{.items[0].metadata.name}")
    
  2. Istio Ingressゲートウェイポッドのエントリを登録します。

    $ kubectl exec -n spire "$SPIRE_SERVER_POD" -- \
    /opt/spire/bin/spire-server entry create \
        -spiffeID spiffe://example.org/ns/istio-system/sa/istio-ingressgateway-service-account \
        -parentID spiffe://example.org/ns/spire/sa/spire-agent \
        -selector k8s:sa:istio-ingressgateway-service-account \
        -selector k8s:ns:istio-system \
        -socketPath /run/spire/sockets/server.sock
    
    Entry ID         : 6f2fe370-5261-4361-ac36-10aae8d91ff7
    SPIFFE ID        : spiffe://example.org/ns/istio-system/sa/istio-ingressgateway-service-account
    Parent ID        : spiffe://example.org/ns/spire/sa/spire-agent
    Revision         : 0
    TTL              : default
    Selector         : k8s:ns:istio-system
    Selector         : k8s:sa:istio-ingressgateway-service-account
    
  3. Istioサイドカーが注入されたワークロードのエントリを登録します。

    $ kubectl exec -n spire "$SPIRE_SERVER_POD" -- \
    /opt/spire/bin/spire-server entry create \
        -spiffeID spiffe://example.org/ns/default/sa/curl \
        -parentID spiffe://example.org/ns/spire/sa/spire-agent \
        -selector k8s:ns:default \
        -selector k8s:pod-label:spiffe.io/spire-managed-identity:true \
        -socketPath /run/spire/sockets/server.sock
    

Istioのインストール

  1. Istioリリースのダウンロード.

  2. Ingressゲートウェイとistio-proxy用のカスタムパッチを使用してIstio構成を作成します。Ingressゲートウェイコンポーネントには、spiffe.io/spire-managed-identity: "true"ラベルが含まれています。

    $ cat <<EOF > ./istio.yaml
    apiVersion: install.istio.io/v1alpha1
    kind: IstioOperator
    metadata:
      namespace: istio-system
    spec:
      profile: default
      meshConfig:
        trustDomain: example.org
      values:
        # This is used to customize the sidecar template.
        # It adds both the label to indicate that SPIRE should manage the
        # identity of this pod, as well as the CSI driver mounts.
        sidecarInjectorWebhook:
          templates:
            spire: |
              labels:
                spiffe.io/spire-managed-identity: "true"
              spec:
                containers:
                - name: istio-proxy
                  volumeMounts:
                  - name: workload-socket
                    mountPath: /run/secrets/workload-spiffe-uds
                    readOnly: true
                volumes:
                  - name: workload-socket
                    csi:
                      driver: "csi.spiffe.io"
                      readOnly: true
      components:
        ingressGateways:
          - name: istio-ingressgateway
            enabled: true
            label:
              istio: ingressgateway
            k8s:
              overlays:
                # This is used to customize the ingress gateway template.
                # It adds the CSI driver mounts, as well as an init container
                # to stall gateway startup until the CSI driver mounts the socket.
                - apiVersion: apps/v1
                  kind: Deployment
                  name: istio-ingressgateway
                  patches:
                    - path: spec.template.spec.volumes.[name:workload-socket]
                      value:
                        name: workload-socket
                        csi:
                          driver: "csi.spiffe.io"
                          readOnly: true
                    - path: spec.template.spec.containers.[name:istio-proxy].volumeMounts.[name:workload-socket]
                      value:
                        name: workload-socket
                        mountPath: "/run/secrets/workload-spiffe-uds"
                        readOnly: true
                    - path: spec.template.spec.initContainers
                      value:
                        - name: wait-for-spire-socket
                          image: busybox:1.36
                          volumeMounts:
                            - name: workload-socket
                              mountPath: /run/secrets/workload-spiffe-uds
                              readOnly: true
                          env:
                            - name: CHECK_FILE
                              value: /run/secrets/workload-spiffe-uds/socket
                          command:
                            - sh
                            - "-c"
                            - |-
                              echo "$(date -Iseconds)" Waiting for: ${CHECK_FILE}
                              while [[ ! -e ${CHECK_FILE} ]] ; do
                                echo "$(date -Iseconds)" File does not exist: ${CHECK_FILE}
                                sleep 15
                              done
                              ls -l ${CHECK_FILE}
    EOF
    
  3. 構成を適用します。

    $ istioctl install --skip-confirmation -f ./istio.yaml
    
  4. Ingressゲートウェイポッドの状態を確認します。

    $ kubectl get pods -n istio-system
    NAME                                    READY   STATUS    RESTARTS   AGE
    istio-ingressgateway-5b45864fd4-lgrxs   1/1     Running   0          17s
    istiod-989f54d9c-sg7sn                  1/1     Running   0          23s
    

    Ingressゲートウェイポッドは、対応する登録エントリがSPIREサーバーで自動的に作成されるため、Readyになります。EnvoyはSPIREから暗号化されたIDを取得できます。

    この構成では、istio-proxyを開始する前に、SPIREがUNIXドメインソケットを作成するのを待つinitContainerもゲートウェイに追加されます。SPIREエージェントの準備ができていない場合、または同じソケットパスで適切に構成されていない場合、IngressゲートウェイのinitContainerは永久に待機します。

  5. ワークロードの例をデプロイします。

    Zip
    $ istioctl kube-inject --filename @samples/security/spire/curl-spire.yaml@ | kubectl apply -f -
    

    spiffe.io/spire-managed-identityラベルが必要なことに加えて、ワークロードはSPIREエージェントソケットにアクセスするためにSPIFFE CSIドライバーボリュームを必要とします。これを実現するには、Istioのインストールセクションのspireポッドアノテーションテンプレートを利用するか、ワークロードのデプロイスペックにCSIボリュームを追加できます。これらの代替案の両方が、以下の例のスニペットで強調表示されています。

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: curl
    spec:
      replicas: 1
      selector:
          matchLabels:
            app: curl
      template:
          metadata:
            labels:
              app: curl
            # Injects custom sidecar template
            annotations:
                inject.istio.io/templates: "sidecar,spire"
          spec:
            terminationGracePeriodSeconds: 0
            serviceAccountName: curl
            containers:
            - name: curl
              image: curlimages/curl
              command: ["/bin/sleep", "3650d"]
              imagePullPolicy: IfNotPresent
              volumeMounts:
                - name: tmp
                  mountPath: /tmp
              securityContext:
                runAsUser: 1000
            volumes:
              - name: tmp
                emptyDir: {}
              # CSI volume
              - name: workload-socket
                csi:
                  driver: "csi.spiffe.io"
                  readOnly: true
    

Istio構成は、Ingressゲートウェイとワークロードポッドに注入されるサイドカーとspiffe-csi-driverを共有し、SPIREエージェントのUNIXドメインソケットへのアクセスを許可します。

発行されたIDを確認するには、ワークロード用にIDが作成されたことを確認するを参照してください。

ワークロードにIDが作成されたことを確認する

次のコマンドを使用して、ワークロード用にIDが作成されたことを確認します。

$ kubectl exec -t "$SPIRE_SERVER_POD" -n spire-server -c spire-server -- ./bin/spire-server entry show
Found 2 entries
Entry ID         : c8dfccdc-9762-4762-80d3-5434e5388ae7
SPIFFE ID        : spiffe://example.org/ns/istio-system/sa/istio-ingressgateway-service-account
Parent ID        : spiffe://example.org/spire/agent/k8s_psat/demo-cluster/bea19580-ae04-4679-a22e-472e18ca4687
Revision         : 0
X509-SVID TTL    : default
JWT-SVID TTL     : default
Selector         : k8s:pod-uid:88b71387-4641-4d9c-9a89-989c88f7509d

Entry ID         : af7b53dc-4cc9-40d3-aaeb-08abbddd8e54
SPIFFE ID        : spiffe://example.org/ns/default/sa/curl
Parent ID        : spiffe://example.org/spire/agent/k8s_psat/demo-cluster/bea19580-ae04-4679-a22e-472e18ca4687
Revision         : 0
X509-SVID TTL    : default
JWT-SVID TTL     : default
Selector         : k8s:pod-uid:ee490447-e502-46bd-8532-5a746b0871d6

Ingress-gatewayポッドの状態を確認します。

$ kubectl get pods -n istio-system
NAME                                    READY   STATUS    RESTARTS   AGE
istio-ingressgateway-5b45864fd4-lgrxs   1/1     Running   0          60s
istiod-989f54d9c-sg7sn                  1/1     Running   0          45s

Ingress-gatewayポッドのエントリを登録すると、EnvoyはSPIREによって発行されたIDを受け取り、すべてのTLSおよびmTLS通信に使用します。

ワークロードIDがSPIREによって発行されたことを確認する

  1. ポッド情報を取得します。

    $ CURL_POD=$(kubectl get pod -l app=curl -o jsonpath="{.items[0].metadata.name}")
    
  2. istioctl proxy-config secretコマンドを使用して、curlのSVID IDドキュメントを取得します。

    $ istioctl proxy-config secret "$CURL_POD" -o json | jq -r \
    '.dynamicActiveSecrets[0].secret.tlsCertificate.certificateChain.inlineBytes' | base64 --decode > chain.pem
    
  3. 証明書を検査し、SPIREが発行者であることを確認します。

    $ openssl x509 -in chain.pem -text | grep SPIRE
        Subject: C = US, O = SPIRE, CN = curl-5f4d47c948-njvpk
    

SPIFFEフェデレーション

SPIREサーバーは、異なるトラストドメインから発信されたSPIFFE IDを認証できます。これはSPIFFEフェデレーションとして知られています。

SPIREエージェントは、Envoy SDS APIを介してフェデレーションバンドルをEnvoyにプッシュするように構成できるため、Envoyは検証コンテキストを使用してピア証明書を検証し、別のトラストドメインからのワークロードを信頼できます。IstioがSPIRE統合を介してSPIFFE IDをフェデレーションできるようにするには、SPIREエージェントのSDS構成を参照し、SPIREエージェント構成ファイルに次のSDS構成値を設定します。

構成説明リソース名
default_svid_nameEnvoy SDSでデフォルトのX509-SVIDに使用するTLS証明書リソース名default
default_bundle_nameEnvoy SDSでデフォルトのX.509バンドルに使用する検証コンテキストリソース名null
default_all_bundles_nameEnvoy SDSですべてのバンドル(フェデレーションを含む)に使用する検証コンテキストリソース名ROOTCA

これにより、EnvoyはSPIREから直接フェデレーションバンドルを取得できるようになります。

フェデレーション登録エントリの作成

  • SPIRE Controller Managerを使用している場合は、ClusterSPIFFEID CRfederatesWithフィールドを、ポッドがフェデレーションするトラストドメインに設定することで、ワークロードのフェデレーションエントリを作成します。

    apiVersion: spire.spiffe.io/v1alpha1
    kind: ClusterSPIFFEID
    metadata:
      name: federation
    spec:
      spiffeIDTemplate: "spiffe://{{ .TrustDomain }}/ns/{{ .PodMeta.Namespace }}/sa/{{ .PodSpec.ServiceAccountName }}"
      podSelector:
        matchLabels:
          spiffe.io/spire-managed-identity: "true"
      federatesWith: ["example.io", "example.ai"]
    
  • 手動登録については、フェデレーションの登録エントリを作成するを参照してください。

SPIREのクリーンアップ

SPIREのHelmチャートをアンインストールして、SPIREを削除します。

$ helm delete -n spire-server spire
$ helm delete -n spire-server spire-crds
この情報は役に立ちましたか?
改善のためのご提案はありますか?

フィードバックありがとうございます!