Kubernetes Istio
- English
- 日本語
この例では、Next-Gen WAF エージェントが Docker のサイドカーコンテナとして実行され、アプリケーションにデプロイされた Istio サービスメッシュと直接統合されます。この設定では、従来の north/south (クライアント-サーバー間) 通信に加えて、east/west (サービス間) 通信の Web リクエストも Next-Gen WAF で検査できるようになります。
Next-Gen WAF エージェントを統合する
Next-Gen WAF エージェントは、各 Pod にサイドカーとしてインストールすることも、特定の要件向けに Service としてインストールすることもできます。
Kubernetes における Next-Gen WAF エージェントの推奨インストール方法は、sigsci-agent を Pod にサイドカーとして統合することです。これは、sigsci-agent を Kubernetes Pod の追加コンテナとして追加することを意味します。サイドカーとして動作することで、エージェントは Pod 内のアプリケーション/Service と共にスケーリングすることになり、個別にスケーリングする必要がなくなります。ただし、状況によっては sigsci-agent コンテナを Service としてインストールし、アプリケーションとは別にスケーリングした方が適している場合もあります。
sigsci-agentコンテナは、使用するインストールタイプやモジュールによってさまざまな方法で構成できます。
コンテナフック preStop を使用すると、Pod のシャットダウンを遅らせ、ドレインタイムアウトを確実に満たすことができます。
preStop: exec: command: - sleep - "30"デフォルトでは、エージェントは予備的な検査のために迅速な起動とパフォーマンス準備を優先します。ただし、ルールや設定データを読み込んだ後にのみトラフィックを検査したい場合、迅速な起動が必ずしも望ましいとは限りません。その場合は、Startup Probe を設定してエージェントの起動を遅延させることを検討してください。
エージェントコンテナイメージを取得および更新する
公式の signalsciences/sigsci-agent コンテナイメージが Docker Hub で利用可能です。
独自のイメージをビルドしたい場合や、イメージをカスタマイズする必要がある場合は、sigsci-agent のビルド手順に従ってください。
これらの手順では、latest バージョンのエージェントを imagePullPolicy: Always で参照しており、ローカルにすでにエージェントが存在する場合でも最新のエージェントバージョンを取得します。これは、ドキュメントが古くならないようにし、このドキュメントを参照するすべての人が古い状態のままのエージェントを使うことを防ぐためです。ただし、インストールの一貫性を維持する必要がある場合や、特定バージョンのエージェントを維持する必要がある場合は、この方法が適さない可能性があります。このような場合は、エージェントのバージョンを指定する必要があります。Docker Hub 上のイメージにはバージョンがタグ付けされており、バージョンのリストは Docker Hub で確認できます。
latest イメージを使用するか特定のバージョンを使用するかにかかわらず、エージェントを最新の状態に保つために考慮すべき項目がいくつかあります。
latestコンテナイメージを使用する
latest イメージを使用することを選択した場合は、エージェントを最新の状態に保つ方法を検討する必要があります。
imagePullPolicy: Alwaysオプションを使用した場合、起動のたびに最新のイメージが取得され、エージェントは継続的に更新を受け取ります。あるいは、起動時に常にプルするのではなく、定期的に手動でローカルキャッシュを更新する方法もあります。
$ docker pull signalsciences/sigsci-agent:latest次に、
latestをimagePullPolicy: Never設定で使用して、起動時にプルが実行されないようにします (上記のように手動でのみ)。- name: sigsci-agentimage: signalsciences/sigsci-agent:latestimagePullPolicy: Never...
バージョン管理されたコンテナイメージを使用する
特定のバージョンのエージェントを使用するには、latest をエージェントのバージョン (ここでは x.xx.x で表されます) に置き換えてください。この場合、イメージは更新されるべきではないため、imagePullPolicy: IfNotPresent に変更することもおすすめします。
- name: sigsci-agent image: signalsciences/sigsci-agent:x.xx.x imagePullPolicy: IfNotPresent ...この方法では、指定したエージェントバージョンがプルされ、ローカルにキャッシュされます。この方法を使用する場合、後からエージェントイメージを更新しやすくするため、Helm などを使ってエージェントイメージをパラメータ化することを推奨します。
コンテナイメージにカスタムタグを使用する
ローカルエージェントイメージにカスタムタグを適用することも可能です。これを行うには、エージェントイメージを (バージョンまたは latest で) プルし、カスタムタグを適用し、そのカスタムタグを設定で使用します。ローカルイメージは手動でのみ更新されるように imagePullPolicy: Never を指定する必要があります。その後、エージェントを最新の状態に保つために、ローカルイメージを定期的に更新する必要があります。
例:
$ docker pull signalsciences/sigsci-agent:latest$ docker tag signalsciences/sigsci-agent:latest signalsciences/sigsci-agent:testing次に、このイメージタグを設定で使用します。
- name: sigsci-agent image: signalsciences/sigsci-agent:testing imagePullPolicy: Never...エージェントコンテナを設定する
エージェントの設定は通常、環境変数を通じて行います。ほとんどの設定オプションは環境変数として利用可能です。環境変数名は、設定オプション名をすべて大文字にし、SIGSCI_ を接頭辞として付け、ダッシュ (-) をアンダースコア (_) に置き換えたものになります。たとえば、max-procs オプションは SIGSCI_MAX_PROCS 環境変数になります。利用可能なオプションの詳細については、エージェント設定ドキュメントを参照してください。
sigsci-agent コンテナには設定が必要ないくつかのオプションがあります。
エージェント認証情報 (Agent Access Key と Agent Secret Key)。
一時ファイルを書き込むためのボリューム。
エージェントの認証情報
sigsci-agent の認証情報は、2つの環境変数で設定されます。これらの変数が設定されていない場合、エージェントは起動しません。
SIGSCI_ACCESSKEYID : Agent Access Key は、エージェントが設定されている Next-Gen WAF コントロールパネル上のサイト (ワークスペース) を識別します。
SIGSCI_SECRETACCESSKEY : Agent Secret Key はエージェントを認証・認可するための共有秘密鍵です。
これらの値は非常に機密性が高いため、Kubernetes の組み込み secrets 機能を使用することを推奨します。この構成では、エージェントは Deployment 設定内にハードコードされた値を読み取るのではなく、Secrets データから値を取得します。これにより、エージェント認証情報のローテーションも、1か所を変更するだけで管理しやすくなります。
secrets 機能を使うには、value オプションではなく valueFrom オプションを使用します。例 :
env: - name: SIGSCI_ACCESSKEYID valueFrom: secretKeyRef: # Update my-site-name-here to the correct site (workspace) name or similar identifier name: sigsci.my-site-name-here key: accesskeyid - name: SIGSCI_SECRETACCESSKEY valueFrom: secretKeyRef: # Update my-site-name-here to the correct site (workspace) name or similar identifier name: sigsci.my-site-name-here key: secretaccesskeysecrets 機能は、Kubernetes 内のさまざまなストアにシークレットを保持します。このガイドでは、例として汎用のシークレットストアを使用していますが、同等のストアであればどれでも使用できます。エージェントのシークレットは、以下の例のような YAML を使用して汎用のシークレットストアに追加できます。
apiVersion: v1kind: Secretmetadata: name: sigsci.my-site-name-herestringData: accesskeyid: 12345678-abcd-1234-abcd-1234567890ab secretaccesskey: abcdefg_hijklmn_opqrstuvwxy_z0123456789ABCDこれは、次のように kubectl を使用してコマンドラインから作成することもできます。
$ kubectl create secret generic sigsci.my-site-name-here \ --from-literal=accesskeyid=12345678-abcd-1234-abcd-1234567890ab \ --from-literal=secretaccesskey=abcdefg_hijklmn_opqrstuvwxy_z0123456789ABCDKubernetes の secrets 機能に関する詳細は、Kubernetes のドキュメントを参照してください。
エージェント用の一時ボリューム
セキュリティ強化のため、sigsci-agent コンテナはルートファイルシステムを読み取り専用としてマウントして実行することを推奨します。ただし、エージェントは RPC 通信用のソケットファイルのような一時ファイルや、位置情報データなどの定期的に更新されるファイルを書き込む必要があります。
読み取り専用のルートファイルシステムでこれを実現するには、書き込み可能なボリュームをマウントする必要があります。この書き込み可能なボリュームは、同じポッド内の他のコンテナにRPCソケットファイルを公開するために共有することもできます。
書き込み可能なボリュームを作成する推奨方法は、組み込みの emptyDir ボリュームタイプを使用することです。これは通常、次の例のように Deployment の volumes セクションで設定します。
volumes: - name: sigsci-tmp emptyDir: {}その後、コンテナはこのボリュームを /sigsci/tmp にマウントします。
volumeMounts: - name: sigsci-tmp mountPath: /sigsci/tmp公式エージェントコンテナイメージのデフォルト設定では、一時ボリュームが /sigsci/tmp にマウントされます。エージェントコンテナ用にこれを変更する必要がある場合、次のエージェント設定オプションもデフォルトから新しいマウント場所に合わせて変更する必要があります。
rpc-addressデフォルトは/sigsci/tmp/sigsci.sockshared-cache-dir(デフォルト :/sigsci/tmp/cache)
外部認可を使用してNext-Gen WAFエージェントを統合する
Istio v1.9 以降では、アクセス制御を外部認可システムに委任する Authorization Policy を設定できるようになりました。
以下のスニペットは Istio のサンプルに沿ったもので、例として使用されている ext-authz サービスを Next-Gen WAF エージェントに置き換えるよう拡張しています。以下のスニペット内で参照されている初期の名前空間やテスト用ワークロードについては Istio のドキュメントを参照してください。特に記載がない限り、すべてのファイルは foo ネームスペースに適用されます。
外部オーソライザーをデプロイしてください
シークレットがすでに適用されていることを前提とします。
apiVersion: v1kind: Servicemetadata: name: sigsci-agent labels: app: sigsci-agentspec: ports: - name: grpc port: 9999 targetPort: 9999 selector: app: sigsci-agent---apiVersion: apps/v1kind: Deploymentmetadata: name: sigsci-agentspec: replicas: 1 selector: matchLabels: app: sigsci-agent template: metadata: labels: app: sigsci-agent spec: containers: - name: sigsci-agent image: signalsciences/sigsci-agent:latest imagePullPolicy: IfNotPresent # Configure the agent to use Envoy gRPC on port 9999 env: - name: SIGSCI_ACCESSKEYID valueFrom: secretKeyRef: # This secret needs added (see docs on sigsci secrets) name: sigsci-agent-accesskey key: accesskeyid - name: SIGSCI_SECRETACCESSKEY valueFrom: secretKeyRef: # This secret needs added (see docs on sigsci secrets) name: sigsci-agent-accesskey key: secretaccesskey # Configure the Envoy to expect response data (if using a gRPC access log config for Envoy) - name: SIGSCI_ENVOY_EXPECT_RESPONSE_DATA value: "1" - name: SIGSCI_ENVOY_GRPC_ADDRESS value: :9999 ports: - containerPort: 9999 securityContext: # The sigsci-agent container should run with its root filesystem read only readOnlyRootFilesystem: true---エージェントが実行されていることを確認します。
$ kubectl logs "$(kubectl get pod -l app=sigsci-agent -n foo -o jsonpath={.items..metadata.name})" -n foo -c sigsci-agent外部認可サービスを定義する
以下のコマンドでメッシュ設定を編集し、拡張プロバイダーの定義を追加します。
$ kubectl edit configmap istio -n istio-systemdata: mesh: |- # Add the following content to define the external authorizers. extensionProviders: - name: "sigsci-agent-ext-authz" envoyExtAuthzGrpc: service: "sigsci-agent.foo.svc.cluster.local" port: "9999" timeout: 0.2s failOpen: true includeRequestBodyInCheck: packAsBytes: true # use `allowPartialMessage: false` if you want to inspect larger payloads allowPartialMessage: true maxRequestBytes: 8192 - name: "sigsci-agent-access-log" envoyHttpAls: service: "sigsci-agent.foo.svc.cluster.local" port: "9999" additionalRequestHeadersToLog: - "x-sigsci-request-id" - "x-sigsci-waf-response" - "accept" - "content-type" - "content-length" additionalResponseHeadersToLog: - "date" - "server" - "content-type" - "content-length"外部認可を有効化する
外部認可を有効化し、ログ記録を適用します。
apiVersion: security.istio.io/v1beta1kind: AuthorizationPolicymetadata: name: ext-authzspec: selector: matchLabels: app: httpbin action: CUSTOM provider: # The provider name must match the extension provider defined in the mesh config. name: sigsci-agent-ext-authz rules: # The rules specify when to trigger the external authorizer. - to: - operation: paths: ["/headers"]# kubectl apply -f logging.yamlapiVersion: telemetry.istio.io/v1alpha1kind: Telemetrymetadata: name: mesh-default namespace: istio-systemspec: accessLogging: - providers: - name: sigsci-agent-access-log# In another terminal curl the httpbin app:$ kubectl exec "$(kubectl get pod -l app=sleep -n foo -o jsonpath={.items..metadata.name})" -c sleep -n foo -- curl -v "http://httpbin.foo:8000/headers" -s
# tail the logs$ kubectl logs -f "$(kubectl get pod -l app=sigsci-agent -n foo -o jsonpath={.items..metadata.name})" -n foo -c sigsci-agentEnvoyFilterを使用してNext-Gen WAFエージェントを統合する
Istio は内部で Envoy プロキシを使用しています。このため、Istio では一般的な Envoy のインストールと同様に、Next-Gen WAF エージェントを gRPC モードで利用できます。Next-Gen WAF エージェントのインストールおよび設定方法は、一般的な Envoy のインストールとほぼ同じですが、Envoy プロキシが自動的にサイドカーとしてデプロイされる点が異なります。その後、Envoy は Istio の EnvoyFilter を使用して設定されます。EnvoyFilter に対する拡張が必要なため、完全な Istio 統合は Istio v1.3 以降でのみ可能です。
Istio ベースのアプリケーションデプロイに Next-Gen WAF サポートを追加するには、以下の手順を実行する必要があります。
Envoy gRPC リスナーモードで設定された
sigsci-agentコンテナを Pod に追加します。emptyDir{}ボリュームを追加して、sigsci-agentが一時的なデータを書き込む場所とします。必要な Envoy 設定を生成される
istio-proxy設定に注入できるよう、アプリケーション用の IstioEnvoyFilterを追加します。
Envoy gRPC サービスとして Next-Gen WAF エージェントを追加する
... containers: # Example helloworld app running on port 8000 without sigsci configured - name: helloworld image: signalsciences/example-helloworld:latest imagePullPolicy: IfNotPresent args: # Address for the app to listen on - localhost:8080 ports: - containerPort: 8080 # Next-Gen WAF agent running in Envoy gRPC mode (SIGSCI_ENVOY_GRPC_ADDRESS configured) - name: sigsci-agent image: signalsciences/sigsci-agent:latest imagePullPolicy: IfNotPresent # Configure the agent to use Envoy gRPC on port 9999 env: - name: SIGSCI_ACCESSKEYID valueFrom: secretKeyRef: # This secret needs added (see docs on sigsci secrets) name: sigsci.my-site-name-here key: accesskeyid - name: SIGSCI_SECRETACCESSKEY valueFrom: secretKeyRef: # This secret needs added (see docs on sigsci secrets) name: sigsci.my-site-name-here key: secretaccesskey # Configure the Envoy to expect response data (if using a gRPC access log config for Envoy) - name: SIGSCI_ENVOY_EXPECT_RESPONSE_DATA value: "1" # Configure the Envoy gRPC listener address on any unused port - name: SIGSCI_ENVOY_GRPC_ADDRESS value: localhost:9999 ports: - containerPort: 9999 securityContext: # The sigsci-agent container should run with its root filesystem read only readOnlyRootFilesystem: trueDeployment に Next-Gen WAF エージェント用の一時ボリュームの定義を追加する
エージェント用の一時ボリュームは、Pod 内の他のコンテナから利用できるよう、組み込みの emptyDir: {} ボリュームタイプを使用して定義する必要があります。
... volumes: # Define a volume where sigsci-agent will write temp data and share the socket file, # which is required with the root filesystem is mounted read only - name: sigsci-tmp emptyDir: {}必要な Envoy 設定を Istio プロキシに注入するための Istio EnvoyFilter オブジェクトを追加する
Istio の EnvoyFilter オブジェクトは、istio-proxy 向けに Envoy の設定を柔軟にカスタマイズできる仕組みです。
以下の例では、EnvoyFilter metadata.name フィールドおよび spec.workloadSelector.labels.app フィールドを、対象となるアプリケーション名に設定する必要があります。追加の Envoy 設定オプションについては、Envoy のインストールガイドを参照してください。これらのセクションは、サンプル YAML 内でコメントとして示されています。
例 example-helloworld_sigsci-envoyfilter.yaml:
# The following adds the required Envoy configuration into the istio-proxy configurationapiVersion: networking.istio.io/v1alpha3kind: EnvoyFiltermetadata: # This needs adjusted to be the app name protected by sigsci name: helloworldspec: workloadSelector: labels: # This needs adjusted to be the app name protected by sigsci app: helloworld
# Patch the Envoy configuration, adding in the required sigsci config configPatches:
# Adds the ext_authz HTTP filter for the sigsci-agent ext_authz API - applyTo: HTTP_FILTER match: context: SIDECAR_INBOUND listener: name: virtualInbound filterChain: filter: name: "envoy.filters.network.http_connection_manager" patch: operation: INSERT_BEFORE value: # Configure the ext_authz filter here: name: envoy.filters.http.ext_authz typed_config: "@type": "type.googleapis.com/envoy.extensions.filters.http.ext_authz.v3.ExtAuthz" transport_api_version: "V3" grpc_service: # NOTE: *SHOULD* use envoy_grpc as ext_authz can use dynamic clusters and has connection pooling envoy_grpc: cluster_name: sigsci-agent-grpc timeout: 0.2s failure_mode_allow: true with_request_body: max_request_bytes: 8192 allow_partial_message: true
# Adds the access_log entry for the sigsci-agent http_grpc_access_log API - applyTo: NETWORK_FILTER match: context: SIDECAR_INBOUND listener: name: virtualInbound filterChain: filter: name: "envoy.filters.network.http_connection_manager" patch: operation: MERGE value: name: "envoy.filters.network.http_connection_manager" typed_config: "@type": "type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager" access_log: # Configure the envoy.http_grpc_access_log here: - name: "envoy.http_grpc_access_log" typed_config: "@type": "type.googleapis.com/envoy.extensions.access_loggers.grpc.v3.HttpGrpcAccessLogConfig" common_config: log_name: "sigsci-agent-grpc" transport_api_version: "V3" grpc_service: # NOTE: *MUST* use google_grpc as envoy_grpc cannot handle a dynamic cluster for ALS (yet) google_grpc: # The address *MUST* be 127.0.0.1 so that communication is intra-pod # Configure the sigsci-agent port number here: target_uri: 127.0.0.1:9999 stat_prefix: "sigsci-agent" timeout: 0.2s additional_request_headers_to_log: # These are required: - "x-sigsci-request-id" - "x-sigsci-waf-response" # These are additional you want recorded: - "accept" - "content-type" - "content-length" additional_response_headers_to_log: # These are additional you want recorded: - "date" - "server" - "content-type" - "content-length"
# Adds a dynamic cluster for the sigsci-agent via CDS for sigsci-agent ext_authz API - applyTo: CLUSTER patch: operation: ADD value: name: sigsci-agent-grpc type: STRICT_DNS connect_timeout: 0.5s http2_protocol_options: {} load_assignment: cluster_name: sigsci-agent-grpc endpoints: - lb_endpoints: - endpoint: address: socket_address: # The address *MUST* be 127.0.0.1 so that communication is intra-pod address: 127.0.0.1 # Configure the agent port here: port_value: 9999その後、Istio を使用して通常どおりアプリケーションをデプロイできます。例 :
$ istioctl kube-inject -f example-helloworld-sigsci.yaml | kubectl apply -f -service/helloworld createddeployment.apps/helloworld created$ kubectl apply -f example-helloworld-sigsci_envoyfilter.yamlenvoyfilter.networking.istio.io/helloworld created$ kubectl get podsNAME READY STATUS RESTARTS AGEhelloworld-7954bb57bc-pfr22 3/3 Running 2 33s$ kubectl get pod helloworld-7954bb57bc-pfr22 -o jsonpath='{.spec.containers[*].name}'helloworld sigsci-agent istio-proxy$ kubectl logs helloworld-7954bb57bc-pfr22 sigsci-agent | head2019/10/01 21:04:57.540047 Signal Sciences Agent 4.39.0 starting as user sigsci with PID 1, Max open files=1048576, Max data size=unlimited, Max address space=unlimited, Max stack size=83886082019/10/01 21:04:57.541987 =====================================================2019/10/01 21:04:57.542028 Agent: helloworld-7954bb57bc-pfr222019/10/01 21:04:57.542034 System: alpine 3.9.4 (linux 4.9.184-linuxkit)2019/10/01 21:04:57.542173 Memory: 1.672G / 3.854G RAM available2019/10/01 21:04:57.542187 CPU: 6 MaxProcs / 12 CPU cores available2019/10/01 21:04:57.542257 =====================================================2019/10/01 21:04:57.630755 Envoy gRPC server on 127.0.0.1:9999 startingPod 内では、以下の3つのコンテナが実行されている点に注意してください : app=helloworld、sigsci-agent、istio-proxy