Kubernetesアンバサダー

この例では、Next-Gen WAF を、Envoy プロキシを基盤とするクラウドネイティブな API ゲートウェイ兼 Kubernetes 用 Ingress コントローラーである Ambassador Edge Stack と統合しています。

Next-Gen WAF エージェントを統合する

Next-Gen WAF エージェントは、各 Pod にサイドカーとしてインストールすることも、特定の要件向けに Service としてインストールすることもできます。

Kubernetes における Next-Gen WAF エージェントの推奨インストール方法は、sigsci-agent を Pod にサイドカーとして統合することです。これは、sigsci-agent を Kubernetes Pod の追加コンテナとして追加することを意味します。サイドカーとして動作することで、エージェントは Pod 内のアプリケーション/サービスと共にスケーリングすることになり、個別にスケーリングする必要がなくなります。ただし、状況によっては sigsci-agent コンテナをサービスとしてインストールし、アプリケーションとは別にスケーリングした方が適している場合もあります。

sigsci-agent コンテナは、インストールタイプや使用するモジュールに応じてさまざまな方法で設定できます。

コンテナフックpreStopを使用して、ポッドのシャットダウンを遅らせ、ドレインタイムアウトを確実に満たすことができます。

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

    次に、latestimagePullPolicy: Never 設定で使用して、起動時にプルが実行されないようにします (上記のように手動でのみ)。

    - name: sigsci-agent
    image: signalsciences/sigsci-agent:latest
    imagePullPolicy: 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 KeyAgent 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: secretaccesskey

secrets機能はKubernetes内のさまざまなストアに秘密を保持します。このガイドでは例として汎用のsecret storeを使用していますが、同等のストアであればどれでも使用できます。エージェントのシークレットは、以下の例のようなYAMLを使用して汎用secret storeに追加できます:

apiVersion: v1
kind: Secret
metadata:
name: sigsci.my-site-name-here
stringData:
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_z0123456789ABCD

Kubernetes の secrets 機能に関する詳細は、Kubernetes のドキュメントを参照してください。

エージェント用の一時ボリューム

セキュリティ強化のため、sigsci-agent コンテナはルートファイルシステムを読み取り専用としてマウントして実行することを推奨します。ただし、エージェントは RPC 通信用のソケットファイルのような一時ファイルや、位置情報データなどの定期的に更新されるファイルを書き込む必要があります。

読み取り専用のルートファイルシステムでこれを実現するには、書き込み可能なボリュームをマウントする必要があります。この書き込み可能なボリュームは、同じ Pod 内の他のコンテナに 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.sock)

  • shared-cache-dir はデフォルトで /sigsci/tmp/cache です

Next-Gen WAF エージェントを Ambassador Edge Stack (AES) に統合する

Next-Gen WAF エージェントは、Datawire の Ambassador Edge Stack (AES) と統合できます。この統合では、エージェントに組み込まれている Envoy 統合機能を使用します。エージェントは、Envoy gRPC リスナーおよび AES の Filter、FilterPolicy、LogService という Kubernetes リソースを通じて設定されます。デプロイおよび設定方法には柔軟性があるため、このガイドは特定の手順に限定せず、独自のデプロイ方法にも適用できる情報を提供することを目的としています。

ドキュメントの例では最新のエージェントバージョンのインストールに言及していますが、これはドキュメントの例が遅れないようにするためです。エージェントのバージョン設定や最新の状態を保つ方法については、エージェントの取得と更新に関するドキュメントを参照してください。

名前空間

デフォルトでは、AES は Kubernetes の ambassador 名前空間にインストールされます。エージェントや AES の背後で動作するアプリケーションは必ずしもこの名前空間で実行する必要はありませんが、このドキュメントの例と異なる構成を使用している場合は、設定時に正しい名前空間を指定する必要があります。このドキュメントでは、次の名前空間を使用しています。

大使

  • アンバサダーの設置に使用されます。

  • すべてのアンバサダーリソース(例:Filter、FilterPolicy、LogService、Mapping)に使用されます。

  • sigsci-agent をサイドカーとして実行する場合に使用

デフォルト

  • AES の背後で動作するすべてのアプリケーションおよび Service に使用

  • スタンドアロンモードで実行した際のエージェント用に使われます。

Ambassador ID

Ambassador Edge Stack は、1つの Kubernetes クラスター内での複数の Ambassador Edge Stack の同時実行をサポートしており、特定のスタックを単一の名前空間に制限する必要はありません。これは ambassador_id 設定によって実現されます。複数の Ambassador Edge Stack を実行する場合は、すべての Ambassador リソース (Filter、LogService、Mapping など) に正しい ambassador_id の値を含める必要があります。これを設定しないと、該当する設定は適用されません。default ID のみで1つのスタックを実行している AES デプロイでは、この値を設定する必要はありません。詳細については、Ambassador ID に関するドキュメントを参照してください。

エージェントをスタンドアロンまたはサイドカーとして実行する

エージェントは、スタンドアロンの Deployment + Service としても、AES Pod 内のサイドカーコンテナとしても実行できます。どちらの方法でも問題ありませんが、Helm を使用している場合は、values ファイルで直接サポートされているためサイドカーとして実行する方が簡単です。また、サイドカーとして実行すると AES と一緒にスケーリングされるという利点があります。そのため、レプリカ数を指定したスケーリングや自動スケーリングを利用している場合は、この方法が推奨されます。

インストール

インストールには2つのタスクがあります。gRPC モードで構成されたエージェントをデプロイすることと、AES がエージェントにトラフィックを送信するように設定することです。

エージェントをデプロイする

エージェントのデプロイは、signalsciences/sigsci-agent コンテナを AES のサイドカーとして、またはスタンドアロンの Service としてデプロイすることで行います。エージェントは Agent Access Key と Agent Secret Key を用いて設定する必要があります。通常、これらは Kubernetes の Secret を通じて設定します。Secret に関する重要な注意点として、Secret はそれを使用する Pod と同じ名前空間に存在している必要があります。そのため、ambassador 名前空間でサイドカーとして実行する場合、Secret も同じ ambassador 名前空間に配置する必要があります。詳細については、エージェント認証情報に関するドキュメントを参照してください。

ambassador 名前空間の Secret の例

apiVersion: v1
kind: Secret
metadata:
# Edit `my-site-name-here`
# and change the namespace to match that which
# the agent is to be deployed
name: sigsci.my-site-name-here
namespace: ambassador
stringData:
# Edit these `my-agent-*-here` values:
accesskeyid: my-agent-access-key-id-here
secretaccesskey: my-agent-secret-access-key-here

Helm を使ったサイドカー構成

AESをHelmで設定するのが最も簡単なデプロイ方法です。Ambassador valuesファイルには、既存のデプロイYAMLファイルを変更しなくても、すでにこれを直接サポートしているからです。AESクイックスタートではこの点が詳しく説明されています。

サイドカーとしてエージェントをインストールするには、カスタム values ファイルに新しい設定行を追加し、その values ファイルを使用して AES をインストールまたはアップグレードします。values ファイルの詳細については、Ambassador Helm チャートのドキュメントを参照してください。これにより、適切な設定のコンテナがサイドカーとして AES Pod に追加されます。

以下の内容を values YAML ファイルに追加します。

sidecarContainers:
- 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 documentation on sigsci secrets)
name: sigsci.my-site-name-here
key: accesskeyid
- name: SIGSCI_SECRETACCESSKEY
valueFrom:
secretKeyRef:
# This secret needs added (see documentation on sigsci secrets)
name: sigsci.my-site-name-here
key: secretaccesskey
# Configure the Envoy to expect response data
- 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
name: grpc
securityContext:
# The sigsci-agent container should run with its root filesystem read only
readOnlyRootFilesystem: true
# Ambassador uses user 8888 by default, but the sigsci-agent container
# needs to run as sigsci(100)
runAsUser: 100
volumeMounts:
- name: sigsci-tmp
mountPath: /sigsci/tmp
volumes:
- name: sigsci-tmp
emptyDir: {}

Helmを使用してAESをアップグレードする例:

$ helm upgrade ambassador \
--values /path/to/ambassador-sigsci_values.yaml \
--namespace ambassador \
datawire/ambassador

あるいは、Helm を使用してマニフェストファイルをレンダリングすることができます。この方法でエージェントサイドカーを追加すると、YAML ファイルを手動で編集するよりもはるかに容易です。修正されたデプロイ YAML は、次の場所にあります。

<output-dir>/ambassador/templates/deployment.yaml

Helm でマニフェストをレンダリングして適用する例

$ helm template \
--output-dir ./manifests \
--values ./ambassador-sigsci_values.yaml \
--namespace ambassador \
datawire/ambassador
$ kubectl apply \
--recursive
--filename ./manifests/ambassador

手動でのサイドカー構成

AES Pod にエージェントを手動でサイドカーとして追加することも可能ですが、Helm を使用してマニフェストをレンダリングする場合と比べて作業量が大幅に増えるため推奨されません。

AES クイックスタートガイドに従って aes.yaml ファイルを変更する必要があります。Helm を使用する手順で説明されている内容に従って、コンテナとボリュームを追加してください。AES クイックスタートガイドおよび Kubernetes や Envoy のドキュメントには、インストールに関する追加の詳細が記載されています。

以下のリソースを変更する必要があります。

apiVersion: apps/v1
kind: Deployment
metadata:
labels:
product: aes
name: ambassador
namespace: ambassador
containers:
volumes:

コンテナはcontainersセクションに追加する必要があり、ボリュームはvolumesセクションに追加する必要があります。

スタンドアローン

スタンドアロンのエージェントをデプロイする場合、以下の例に示すように、エージェント用の Deployment リソースと Service リソースを追加するだけです。

apiVersion: v1
kind: Service
metadata:
name: sigsci-agent
# You may want it running in the ambassador namespace
#namespace: ambassador
labels:
service: sigsci-agent
spec:
type: ClusterIP
ports:
- name: sigsci-agent
port: 9999
targetPort: grpc
selector:
service: sigsci-agent
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: sigsci-agent
# You may want it running in the ambassador namespace
#namespace: ambassador
spec:
replicas: 1
selector:
matchLabels:
service: sigsci-agent
template:
metadata:
labels:
service: 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 documentation on sigsci secrets)
name: sigsci.my-site-name-here
key: accesskeyid
- name: SIGSCI_SECRETACCESSKEY
valueFrom:
secretKeyRef:
# This secret needs added (see documentation on sigsci secrets)
name: sigsci.my-site-name-here
key: secretaccesskey
# Configure the Envoy to expect response data
- name: SIGSCI_ENVOY_EXPECT_RESPONSE_DATA
value: "1"
# Configure the Envoy gRPC listener address on any unused port
- name: SIGSCI_ENVOY_GRPC_ADDRESS
value: 0.0.0.0:9999
ports:
- containerPort: 9999
name: grpc
securityContext:
# The sigsci-agent should run with its root filesystem read only
readOnlyRootFilesystem: true
volumeMounts:
- name: sigsci-tmp
mountPath: /sigsci/tmp
volumes:
- name: sigsci-tmp
emptyDir: {}

詳細については、KubernetesとEnvoyのドキュメントをご参照ください。

エージェントにトラフィックを送信します

AES がエージェントへデータを送信できるようにするには、3つの Ambassador リソースを設定する必要があります。基盤となる Envoy インストールでの各設定の詳細については、Envoy の設定ドキュメントを参照してください。以下のガイドでは、Ambassador に同梱されている quote サービスの例を使用します。

フィルター

Filter リソースは、Envoy に外部認可 (ext_authz) フィルターを追加するために使用されます。このフィルターは、FilterPolicy に一致する受信リクエストを検査します。

Next-Gen WAF エージェントでは、Ambassador の設定内で AuthService が定義されている必要があります。定義されていない場合、エージェントはリクエストデータを受信できません。AuthService はデフォルトで有効になっているはずですが、エージェントにリクエストが届かない場合は、kubectl get authservice を実行して AuthService が有効であることを確認してください。

auth_service 設定で使用する名前空間は、エージェントがデプロイされている名前空間です。このガイドでは、サイドカーエージェントに ambassador 名前空間を、スタンドアロンエージェントに default 名前空間を使用します。auth_service URL の形式は次のとおりです。

agent-hostname[.namespace]:agent-port

  • サイドカー: auth_service: localhost:9999

  • スタンドアローン: auth_service: sigsci-agent.default:9999

Filter YAML の例

# Filter defines an external auth filter to send to the agent
kind: Filter
apiVersion: getambassador.io/v3alpha1
metadata:
name: sigsci
namespace: ambassador
annotations:
getambassador.io/resource-changed: "true"
spec:
External:
# Sidecar agent:
auth_service: localhost:9999
# Standalone sigsci-agent service in default namespace:
#auth_service: sigsci-agent.default:9999
path_prefix: ""
tls: false
proto: grpc
protocol_version: v3
include_body:
max_bytes: 8192
allow_partial: true
failure_mode_allow: true
timeout_ms: 100000

FilterPolicy

FilterPolicy リソースは、エージェントによって検査されるパスをマッピングします。すべてのトラフィック (path: /*) を対象にすることも、サブセット (path: /app1/*) に限定することも可能です。ただし、各サブセットは必ず同一のエージェントにマッピングされなければならないという制限があります。これは、LogService に FilterPolicy のようなパスベースのフィルターがなく、リクエストを処理したエージェントと同じエージェントに、対応するレスポンスデータを必ずルーティングする必要があるためです。

すべてのトラフィックをエージェントにルーティングする例

# FilterPolicy defines which requests go to sigsci
kind: FilterPolicy
apiVersion: getambassador.io/v3alpha1
metadata:
namespace: ambassador
name: sigsci-policy
annotations:
getambassador.io/resource-changed: "true"
spec:
rules:
- host: "*"
# All traffic to the sigsci-agent
path: "/*"
filters:
# Use the same name as the Filter above
- name: sigsci
namespace: ambassador
onDeny: break
onAllow: continue
ifRequestHeader: null
arguments: {}

複数のルールを使用して、トラフィックのサブセットをエージェントにルーティングすることができます。ただし、前述の制約により、すべてのルールは同一のエージェントに送信されなければなりません。

トラフィックのサブセットをエージェントにルーティングする例

# FilterPolicy defines which requests go to the sigsci-agent
kind: FilterPolicy
apiVersion: getambassador.io/v3alpha1
metadata:
namespace: ambassador
name: sigsci-policy
annotations:
getambassador.io/resource-changed: "true"
spec:
rules:
# /app1/* and /app2/* to the sigsci-agent
- host: "*"
path: "/app1/*"
filters:
# Use the same name as the Filter above
- name: sigsci
namespace: ambassador
onDeny: break
onAllow: continue
ifRequestHeader: null
arguments: {}
- host: "*"
path: "/app2/*"
filters:
# Use the same name as the Filter above
- name: sigsci
namespace: ambassador
onDeny: break
onAllow: continue
ifRequestHeader: null
arguments: {}

LogService

LogService リソースは、Envoy に gRPC Access Log Service を追加するために使用されます。これにより、送信されるレスポンスデータが検査され、シグナルが検出された場合に記録されます。また、HTTP_4XXHTTP_5XX といった異常シグナルにも使用されます。

service 設定で使用する名前空間は、エージェントがデプロイされている名前空間ですこのガイドでは、サイドカーエージェントに ambassador 名前空間を、スタンドアロンエージェントに default 名前空間を使用します。service URL の形式は次のとおりです。

agent-hostname[.namespace]:agent-port

  • サイドカー : service: localhost:9999

  • スタンドアロン : service: sigsci-agent.default:9999

例:

# Configure the access log gRPC service for the response
# NOTE: There is no policy equiv here, so all requests are sent
apiVersion: getambassador.io/v3alpha1
kind: LogService
metadata:
namespace: ambassador
name: sigsci-agent
spec:
# Sidecar agent
service: localhost:9999
# Standalone sigsci-agent service in default namespace:
#service: sigsci-agent.default:9999
driver: http
driver_config:
additional_log_headers:
### Request headers:
# Required:
- header_name: "x-sigsci-request-id"
during_request: true
during_response: false
during_trailer: false
- header_name: "x-sigsci-waf-response"
during_request: true
during_response: false
during_trailer: false
# Recommended:
- header_name: "accept"
during_request: true
during_response: false
during_trailer: false
- header_name: "date"
during_request: false
during_response: true
during_trailer: true
- header_name: "server"
during_request: false
during_response: true
during_trailer: true
### Both request/response headers:
# Recommended
- header_name: "content-type"
during_request: true
during_response: true
during_trailer: true
- header_name: "content-length"
during_request: true
during_response: true
during_trailer: true
grpc: true
protocol_version: v3