先日のリリースでVPC Service Controls(VPCSC)のIngress/Egress PolicyがGAになったので、これを利用してみます。

本当はできるのかもしれませんが、従来のVPCSCではCloud Storage API全体の制御は可能で、読み込みだけは許可するような細かい設定はできない、というのが筆者の理解です。

いずれにせよ、Ingress Policyを使えばそれが可能になるか、とても簡単に設定できるようになるはず、というモチベーションで検証を始めました。

題材は、「Cloud Storage APIに特定のIPアドレスのみアクセスを許可する」を従来の方法で実現し、続いて「読み込みはどこからでも可能」になるようにIngress Policyを作成していきます。

VPCSCは組織リソースなので、試す際には組織への権限が必要です。
今回は筆者のオレオレCloud Identity組織で試すことにします。

従来のVPCSCを設定する

まずはIngress Policyを使わずにお題を実現します。
VPCSCでアクセス制御をするためには、Access Context Manager(ACM)で次の要素が必要です。

  • Access Context Manager Policy
  • Access Context Manager Access Level
  • Access Context Manager Service Perimeter

上から順番に作成していきます。

ACM Policy

$ gcloud access-context-manager policies create \
    --organization=<ORGANIZATION_ID> --title="Default Policy"
Create request issued
complete...done.
Created.

$ gcloud access-context-manager policies list \
  --organization=<ORGANIZATION_ID>
NAME          ORGANIZATION  TITLE           ETAG
903403894251  <ORGANIZATION_ID>  Default Policy  cb8749aec4b343a3

ACM Access Level

今回は特定のIPアドレスからのアクセスのみを許可したいので、まずは接続元のIPアドレスを調べてください。
この記事では 119.106.25.160 とします。
Access Levelのルールはyamlで記述することが必要で、今回は次のような簡素なもので十分です。

- ipSubnetworks:
  - 119.106.25.160/32

これを access-level.yaml という名前で保存して、Access Levelを作成します。
※端末のIPv6が有効になっているとそのアドレスで接続してしまうので、何か意図しない挙動の場合は端末のIPv6設定を確認してみてください

$ gcloud access-context-manager levels create "allow_from_authorized_ips" \
    --basic-level-spec=access-level.yaml \
    --combine-function=AND \
    --title="Allow from authorized IPs" \
    --policy=903403894251

Cloud Consoleからは次のように確認できます。

ACM Service Perimeter

最後にService Perimeterを作成します。
Cloud Storage APIを対象に、先程作成したAccess Levelを紐付けます。
事前に対象のGCSバケットが存在するGCPプロジェクト番号を控えておきましょう。(※ プロジェクトIDではありません)

$ gcloud access-context-manager perimeters create restrict_contents_access \
    --title="Restrict Contents Access" \
    --resources=projects/<YOUR_PROJECT_NUMBER> \
    --restricted-services=storage.googleapis.com \
    --access-levels=allow_from_authorized_ips \
    --policy=903403894251

ここまでやると、接続元IPからはCloud Storageが利用できるのに対して、Cloud Shellなどからは次のようにアクセスが拒否されるようになります。

$ gsutil ls
AccessDeniedException: 403 Request is prohibited by organization\'s policy.
vpcServiceControlsUniqueIdentifier: ...

ここまでが今までのVPCSCの使い方ですが、Service PerimeterをIngress Policyを利用するように変更して、読み込みだけはどこからでもできるようにしてみます。

Ingress Policy

まずはIngress Policyを使ってここまでと同じことをしてみます。
ACM PolicyとACM Access LevelはIngress Policyでも利用するので、これらを残して既存のService Perimeterを一旦削除します。

$ gcloud access-context-manager perimeters delete restrict_contents_access

Ingress Policyでもアクセスルールを記述したyaml設定ファイルが必要なので、ドキュメントに従ってingress-policy.yamlという名前で作成すると、次のようになります。

- ingressFrom:
    identityType: ANY_IDENTITY
    sources:
    - accessLevel: accessPolicies/903403894251/accessLevels/allow_from_authorized_ips
  ingressTo:
    operations:
    - serviceName: storage.googleapis.com
      methodSelectors:
      - method: "*"
    resources:
    - projects/350155719165

これは、該当のAccess Levelを満たし、認可されていれば Cloud Storage APIの全ての操作が許可されることを示しています。
この設定はこれまでのものとやっていることは何も変わらないので、許可設定に特に変更はありません。
ただ、Ingress Policyのイメージを掴むことはできるはずです。
Access Levelを定義して、Cloud Storage APIの特定のmethodを許可できそうなことを理解することが重要です。
このIngress Policyを使ってService Perimeterを作成するには、次のようにします。

$ gcloud access-context-manager perimeters update restrict_contents_access \
    --title="Restrict Contents Access" \
    --set-ingress-policies=ingress-policy.yaml \
    --set-access-levels=allow_from_authorized_ips \
    --set-resources=projects/350155719165 \
    --set-restricted-services=storage.googleapis.com \
    --policy=903403894251

さて、ここからが本題です。
ここまでは、許可されていないIPアドレスからはCloud Storage APIの全ての操作が拒否されましたが、せめてバケットの一覧だけは取得させてあげることにします。

まずAccess Levelを考えると、今回はどんなIPアドレスからでも許可したいので、新規に作成する必要はありません。
念の為記載しておくと、APIへの認証と認可は前提となるので、GCSバケットリストを全世界に公開することにはなりません。

次に考えるのは上記Ingress Policyの設定の中の methodに該当する部分です。
ここには、Cloud Storage APIの中の許可したいものを記述する必要があります。
各APIが対応しているmethodの一覧はこちらにあります。
Cloud Storage APIの中に google.storage.buckets.list があるので、今回はこれのみを許可します。

これらを踏まえてIngress Policyの設定ファイルと書くと次のようになります。

- ingressFrom:
    identityType: ANY_IDENTITY
    sources:
    - accessLevel: "*"
  ingressTo:
    operations:
    - serviceName: storage.googleapis.com
      methodSelectors:
      - method: "google.storage.buckets.list"
    resources:
    - projects/350155719165

これを先程と同様にupdateで適用すると、Cloud Storage APIへの認可がある前提で次のことが実現できているはずです。

  • 特定のIPアドレスからは全ての操作を許可
  • 許可IPアドレス外でも、GCSバケットの一覧は許可

以上でIngress Policyの紹介を終わります。

Ingress Policyは、元々は境界ブリッジを利用していた設定を簡素化するものであるとドキュメントでは説明されているので、プロジェクトを跨ぐような設定をする場合にも利用した方が良さそうということだけ理解して、そのうち試そうという心構えだけしています。