TT Lab
はじめる
学ぶ 学習パス コース

ICA — Istio認定アソシエイト

ICA模擬試験A

TT Labで続きを見る

ICA模擬試験Aです。制限時間は120分、課題は17個、合格ラインは68%です。 部分点制なので、行き詰まった課題は飛ばして、あとで戻ってくるほうがよいです。

模擬試験なので、ヒントと正解を見ずに、まず最後まで解いてみてください。 時間が足りなくて解けなかったことと、分からなくて解けなかったことは別の問題で、その2つを区別して初めて、 次に何を勉強するかが決まります。すべて解いて採点したあとに開いてください。

実際の試験環境

試験中に、istio.io/docs、istio.io/blog、kubernetes.io/docsを見られます。 istio.io/search/でドキュメントサイトの中を検索することは許可されますが、外部の検索 結果をクリックしてはいけません。kエイリアスとbashの自動補完、そしてistioctlの 自動補完は、すでに設定されています。課題ごとに指定されたホストへsshして 作業し、入れ子のsshはサポートされません。ターミナルのコピーはCtrl+Shift+C、 貼り付けはCtrl+Shift+Vです。

この模擬試験の環境

Podの中の1人用クラスターで、そのまま作業します(sshは不要です)。 kube-apiserverは本物なので、誤ったマニフェストは実際に拒否されますが、サイドカーは 起動せず、トラフィックも流れません。採点は、クラスターに残された設定を 読み直して行います。

課題1が、残りのほとんどの前提です。Istioのリソースの種類が登録される前は、 kubectl applyがVirtualServiceを受け付けてくれません。まず終わらせてください。


1. デフォルトプロファイルのIstioのインストールマニフェストを作成して、/root/ica/install/manifest.yaml に保存してください。そして、そのマニフェストの中のCustomResourceDefinitionだけを選んで、 クラスターに登録してください。この環境ではistiodのPodが起動しないので、必要なのは APIの型だけです。

2. ネームスペースを3つ作成して、サイドカー注入のラベルを付けてください。

3. Podのレベルで、ネームスペースの決定を覆してください。2つのDeploymentとも、 レプリカ1つ、イメージnginx:1.27-alpineです。

4. ica-shopにレビューのサービスを3つのバージョンで立ち上げて、subsetを定義してください。

5. ica-shopにVirtualService reviewsを作成してください。ホストは reviews.ica-shop.svc.cluster.localで、条件のないルール1つで、subset v1に 80、subset v2に20を分けます。

6. 課題5のVirtualService reviewsの前に、ルールを2つ追加して、合計3つに してください。順序が採点の対象です。

  1. ヘッダーend-userがちょうどtesterならsubset v3
  2. uriのプレフィックスが/api/v2で、かつメソッドがGETならsubset v2
  3. 課題5の重みのルールが、条件のない最後のルールとして残ります

7. 同じVirtualService reviewsの最後(条件のない)のルールに、レジリエンスの設定を 付けてください。全体のタイムアウト2s、リトライ3回、試行ごとのタイムアウト500ms、リトライの 条件は5xx・reset・connect-failureです。

8. DestinationRule reviewsのtrafficPolicyに、上限と外れ値の検知を 追加してください。

9. ica-shopにIngressを立ててください。

10. mTLSをメッシュ全体で強制しつつ、古いネームスペースだけを例外にしてください。

11. ica-legacyのlegacy-apiワークロードだけをSTRICTに上げて、8080ポートは 例外にしてください。PeerAuthenticationの名前はlegacy-api、selectorは app: legacy-api、mtls.modeはSTRICT、portLevelMtlsの8080は DISABLEです。

12. ica-shopに認可ポリシーを2つ作成してください。どちらもselectorは app: reviewsです。

13. ica-shopのapp: reviewsワークロードに、JWT検証を付けてください。

14. あるチームが、ica-fixネームスペースに書き込むと言って、次のVirtualServiceを 1つだけ渡してきました。このままでは、istioctl analyzeがエラーを出します。何が抜けているかを 診断して補い、istioctl analyze -n ica-fixがErrorを1つも出さないように してください。

apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
  name: payments
  namespace: ica-fix
spec:
  hosts:
    - payments.ica-fix.svc.cluster.local
  http:
    - route:
        - destination:
            host: payments.ica-fix.svc.cluster.local
            subset: stable

補うものの仕様は次のとおりです。Deployment paymentsはPodのラベル app=paymentsとversion=v1、Service paymentsはポート9090にポート名 http、DestinationRule paymentsは上と同じFQDNをhostに置き、subset stableをversion: v1で定義します。このネームスペースに、課題と無関係な リソースを残さないでください。残ると、analyzeがそれまで拾います。

15. ica-triageネームスペースに次のVirtualServiceを適用したところ、 x-beta: trueヘッダーを付けても、常にstableへ行きます。原因を診断して直したものを 適用してください。ルールは2つのままにします。

apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
  name: checkout
  namespace: ica-triage
spec:
  hosts:
    - checkout.ica-triage.svc.cluster.local
  http:
    - route:
        - destination:
            host: checkout.ica-triage.svc.cluster.local
            subset: stable
    - match:
        - headers:
            x-beta:
              exact: "true"
      route:
        - destination:
            host: checkout.ica-triage.svc.cluster.local
            subset: beta

16. 次のポリシーを入れたあと、ica-triageのpaymentsワークロードが、すべてのリクエストを 拒否します。原因を診断し、cluster.local/ns/ica-triage/sa/frontendが POSTで/pay*にアクセスすることだけを許可するように直してください。

apiVersion: security.istio.io/v1
kind: AuthorizationPolicy
metadata:
  name: payments-allow
  namespace: ica-triage
spec:
  selector:
    matchLabels:
      app: payments
  action: ALLOW
  rules: []

17. ica-triageに次の2つのリソースを置いたところ、ordersを呼び出す側がすべて 失敗します。サーバー側の要求はそのままにして、クライアント側を直してください。

apiVersion: security.istio.io/v1
kind: PeerAuthentication
metadata:
  name: default
  namespace: ica-triage
spec:
  mtls:
    mode: STRICT
---
apiVersion: networking.istio.io/v1
kind: DestinationRule
metadata:
  name: orders
  namespace: ica-triage
spec:
  host: orders.ica-triage.svc.cluster.local
  trafficPolicy:
    tls:
      mode: DISABLE

課題15から17までのica-triageには、ワークロードを作る必要はありません。直すべき ものは設定です。

メッシュのAPIの型をクラスターに登録する

istioctl manifest generateは、チャートをバイナリの中に抱えているので、インターネットなしでも動作します。その結果にはistiodとServiceまで入っていますが、この環境で必要なのはCRDだけなので、kindで絞り込んでください。適用するときは、--server-sideを使ってください。Istio CRDはアノテーションが大きく、通常のapplyのlast-applied-configurationの上限(262144バイト)を超えます。

ネームスペースごとにサイドカー注入のラベルを付ける

リビジョンのラベルとistio-injectionラベルが1つのネームスペースに一緒にあると、istio-injectionが勝ちます。そのため、リビジョンに移す途中で以前のラベルを消さないと、新しいリビジョンが静かに無視されます。消すときは、ラベル名のあとにマイナス記号を付けます。

Podのレベルで注入の有無を覆す

sidecar.istio.io/injectは、Podテンプレートのラベルに付けます。Deployment自体のラベルやアノテーションではありません。値は、必ず引用符で囲んだ文字列である必要があります。Kubernetesのラベルの値は文字列しか受け付けないので、引用符なしで書くと、apiserverが拒否します。

バージョンごとのワークロードとsubsetを作成する

Serviceのselectorにversionを入れると、1つのバージョンだけが対象になり、重みによる分配がそもそも不可能になります。バージョンを分けるのは、DestinationRuleのsubsetの役割です。subsetのlabelsは、subset名ではなく、Podのラベルと文字どおりに同じである必要があり、spec.hostは、短い名前の代わりにFQDNで書いてください。Serviceのポート名は、Istioがプロトコルを判別する根拠です。

重みで80対20に分ける

重みは、route配列の各destinationに付き、合計が100である必要があります。このルールにはmatchを置かないでください。あとの課題で、条件の付いたルールがこの前に入ってきて、条件のないルールは、常に一番最後にある必要があります。

具体的なルールをcatch-allの前に置く

ルールは上から下へ評価され、最初にマッチしたものが勝ちます。条件のないルールが一番前にあると、あとのルールは永遠に評価されません。そして、2つの条件をANDで結ぶには、同じmatchブロックの中に並べて書く必要があります。ブロックを2つに分けると、ORになります。

タイムアウトとリトライの関係を合わせる

timeoutは、リトライを含む全体のデッドラインです。perTryTimeout掛ける試行回数がtimeoutを超えると、最後の試行は開始もできずに打ち切られます。ここでは、500ms掛ける3が1.5秒なので、2秒以内に収まります。retryOnは、カンマでつないだ文字列で、空にしておくと、どの失敗でリトライするかが決まりません。

コネクションプールの上限と外れ値の検知を設定する

2つは同じtrafficPolicyの中にありますが、行うことが違います。connectionPoolは、こちらから出ていく負荷を防ぎ、outlierDetectionは、相手のインスタンスが5xxを出し続けると、しばらく外します。maxEjectionPercentを書かないと、フィールドがそもそも保存されないので、値を明示してください。前の課題で作ったloadBalancerを、消さないように気をつけてください。

Ingressゲートウェイを立てる

Gatewayは、ポートを開けるだけで、ルーティングは行いません。VirtualServiceのspec.gatewaysに名前を書いて結び付けないと、そのルールはメッシュ内部にだけ適用され、外部のリクエストは404を受け取ります。httpsRedirectは、80ポートのserverのtlsの下に置きます。証明書は、ゲートウェイ用Podのネームスペースで、credentialNameで探されます。

メッシュ全体のSTRICTとネームスペースの例外

PeerAuthenticationは、3つの層でかかります。selectorがなく、ルートネームスペース(istio-system)にあればメッシュ全体、selectorなしで別のネームスペースにあれば、そのネームスペース全体、selectorがあればワークロードです。狭い範囲が、広い範囲に勝ちます。全体のポリシーにselectorを付けた瞬間に、それはもう全体ではありません。

ワークロードのSTRICTにポートの例外を置く

portLevelMtlsは、selectorがあるワークロードのポリシーでのみ動作します。selectorなしで書くと、apiserverが拒否します。そして、ここに書くポート番号は、Serviceのポートではなく、Podのコンテナポートです。Serviceのポートを書くと、例外がどこにもかからず、その事実はエラーなしで静かに見過ごされます。

ALLOWとDENYのポリシーを使い分ける

DENYはALLOWより先に評価され、1つでもかかればそこで終わりです。評価の順序はCUSTOM、DENY、ALLOWです。principalはServiceAccountのSPIFFEアイデンティティで、形式はcluster.local/ns/<네임스페이스>/sa/<서비스계정>です(プレースホルダーはネームスペースとServiceAccountです)。パスの末尾のアスタリスクは、プレフィックスのマッチです。

JWT検証とトークンの要求を一緒にかける

RequestAuthenticationは、トークンがあれば検証するだけで、トークンのないリクエストは、そのまま通します。トークンを要求するには、requestPrincipalsを使うAuthorizationPolicyを一緒にかける必要があります。requestPrincipalsの形式は、issuerとsubjectをスラッシュでつないだもので、発行者だけを制限したいなら、後ろをアスタリスクにします。

analyzeが指摘するものを補う

istioctl analyze -n ica-fixをまず実行して、何を見つけられないと言っているかを読んでください。IST0101は、参照したhost、またはhostとsubsetの組が見つからなかったという意味です。Serviceがなくても、DestinationRuleにそのsubsetがなくても、同じコードが出ます。1つずつ補ってもう一度実行すると、残りが減っていくのが分かります。

到達しないルールを生き返らせる

ルールは上から下へ評価され、最初にマッチしたものが勝ちます。条件のないルールは、すべてのリクエストにマッチするので、それが一番前にあると、あとのルールは、どんなリクエストでも評価されません。エラーは何も出ず、設定は有効なまま残るので、目で見つけるしかありません。

すべてのリクエストをブロックする、空のALLOWポリシーを直す

AuthorizationPolicyがあるワークロードに1つでもかかると、そのワークロードはデフォルト拒否に変わります。その状態でALLOWのルールが空だと、どのリクエストもルールにかからず、すべて拒否されます。ポリシーがないことと、空のポリシーがあることは、正反対の結果を出します。

サーバーの要求と食い違ったクライアントのTLSを直す

PeerAuthenticationは、サーバーが何を受け入れるかを決め、DestinationRuleのtrafficPolicy.tlsは、クライアントがどう接続するかを決めます。サーバーがSTRICTなのにクライアントがDISABLEだと、平文で接続して切断されます。どちらも有効な設定なので、どちらもエラーを出さないという点が、この障害を難しくします。サイドカーが代わりに証明書を扱ってくれるモードを選んでください。