トラブルシューティング

このページでは、VPC Service Controls を構成しようとした際に発生する可能性があるさまざまな問題について記載しています。

VPC Service Controls のエラーを探す

このセクションでは、監査ログで VPC エラーを検出する 2 つの方法について説明します。エラーの特定には、エラーの一意の ID を使用するか、メタデータを使用します。

エラーの一意の ID を使用する

VPC Service Controls によって生成されるエラーには、関連する監査ログを識別するために使用される一意の ID が含まれます。

以下の説明では、Logging のドキュメントに記載されている用語を使用します。詳細については、基本ログフィルタをご覧ください。

一意の ID を使用してエラーに関する情報を取得するには:

  1. Cloud Console で、エラーの原因と考えられるサービス境界内のプロジェクトの [Stackdriver Logging] ページに移動します。

    [Stackdriver Logging] ページに移動

  2. 検索フィルタ ボックスに、エラーの一意の ID を入力します。

メタデータを使用してログをフィルタする

VPC Service Controls に関連するエラーを見つけるには、Cloud Logging を使用します。

Console

以下の説明では、Logging のドキュメントに記載されている用語を使用します。詳細については、基本ログフィルタをご覧ください。

過去 24 時間に発生した VPC Service Controls のエラーを Logging で探すには以下の手順に従ってください。

  1. Google Cloud Console で、サービス境界内のプロジェクトの [Stackdriver Logging] ページに移動します。

    [Stackdriver Logging] ページに移動

  2. 検索フィルタ ボックスに、次のように入力します。

    protoPayload.metadata.@type:"type.googleapis.com/google.cloud.audit.VpcServiceControlAuditMetadata"
    
  3. リソースの基本セレクタ メニューで、[監査対象リソース] を選択します。

  4. 時間範囲セレクタのプルダウン メニューで、[過去 24 時間] を選択します。

  5. 別の期間に発生した VPC Service Controls のエラーを探す場合は、時間範囲セレクタ プルダウン メニューで範囲を変更します。

gcloud

過去 24 時間の VPC Service Controls のエラーを確認するには:

gcloud logging read 'protoPayload.metadata.@type:"type.googleapis.com/google.cloud.audit.VpcServiceControlAuditMetadata"'

デフォルトでは、read コマンドは過去 24 時間に制限されています。別の期間の VPC Service Controls のログを取得するには、次のいずれかのコマンドを使用します。

現在の日付を基準にログを制限するには:

gcloud logging read \
  'protoPayload.metadata.@type:"type.googleapis.com/google.cloud.audit.VpcServiceControlAuditMetadata"' \
  --freshness=DURATION

ここで

  • DURATION は書式付きの期間です。フォーマットの詳細については、gcloud相対期間 / 時間形式をご覧ください。

たとえば、先週発生したすべての VPC Service Controls エラーを取得するには、次のように入力します。

gcloud logging read \
  'protoPayload.metadata.@type:"type.googleapis.com/google.cloud.audit.VpcServiceControlAuditMetadata"' \
  --freshness=7d

特定の期間にログを制限するには:

gcloud logging read \
  'protoPayload.metadata.@type:"type.googleapis.com/google.cloud.audit.VpcServiceControlAuditMetadata" AND
  timestamp>="DATETIME" AND
  timestamp<="DATETIME"'

ここで

  • DATETIME は書式付きの日付 / 時刻文字列です。フォーマットの詳細については、gcloud絶対日付 / 時刻形式をご覧ください。

たとえば、2019 年 3 月 22 日から 2019 年 3 月 26 日までに発生したすべての VPC Service Controls エラーを取得するには、次のように入力します。

gcloud logging read \
  'protoPayload.metadata.@type:"type.googleapis.com/google.cloud.audit.VpcServiceControlAuditMetadata" AND
  timestamp>="2019-03-22T23:59:59Z" AND
  timestamp<="2019-03-26T00:00:00Z"'

サポートされていないサービス

VPC Service Controls でサポートされているプロダクトとサービスの詳細については、サポートされているプロダクトのページをご覧ください。

gcloud コマンドライン ツールまたは Access Context Manager API を使用して、サポートされていないサービスを制限しようとするとエラーが発生します。

サポートされているサービスのデータに対するプロジェクト間のアクセスは、VPC Service Controls によってブロックされます。また、制限付き VIP を使用して、サポートされていないサービスを呼び出すワークロードをブロックできます。

共有 VPC

共有 VPC を使用する場合、共有 VPC ネットワークに属するプロジェクトを含むサービス境界には、そのネットワークをホストするプロジェクトも含まれる必要があります。共有 VPC ネットワークに属するプロジェクトがホスト プロジェクトと同じ境界にない場合、サービスは期待どおりに動作しないか、完全にブロックされる可能性があります。

共有 VPC ネットワーク ホストが、ネットワークに接続されているプロジェクトと同じサービス境界にあることを確認してください。

境界間のリクエスト

通常、アクセスレベルは、サービス境界内部の保護されたリソースに対し、サービス境界の外部からのリクエストを許可するために使用されます。

ただし、別の境界内の保護されたリソースに対する境界内のプロジェクトからのリクエストは、アクセスレベルによって通常は許可されるリクエストの場合でも拒否されます。

たとえば、境界 1 のプロジェクト A がプロジェクト B にあるリソースをリクエストするとします。プロジェクト B にあるそのリソースは、境界 2 で保護されています。プロジェクト A は境界内にあるため、通常は境界 2 のアクセスレベルによって許可されるような保護されたリソースに対するリクエストであっても、そのリクエストは拒否されます。

境界間のリクエストを円滑に進めるには、次の 2 つの方法があります。

  • 境界ブリッジを使用する。ブリッジを使用すると、異なる境界の 2 つ以上のプロジェクトで、それらのプロジェクト内の任意のサービスに対するリクエストを行うことが可能になります。こうしたリクエストは、サービスが境界によって保護されていても許可されます。

  • リクエスト元のサービスと対象のリソースの両方が境界により保護されないようにする。このシナリオでは、サービスが保護されないためオペレーションは成功します。

エラーの原因が VPC Service Controls かどうか判断する

VPC Service Controls は Google Cloud の特定の低レベル プロパティを変更するため、複数のサービスに影響が連鎖する可能性があります。このため、調査の範囲を明確にしないとデバッグが難しくなります。

VPC Service Controls に起因するエラーかどうかを特定するには、VPC Service Controls が有効で、使用するプロジェクトとサービスに適用されているかどうかを確認します。これは、gcloud コマンドライン ツールまたは Cloud Console で行うことができます。

サービス境界内のプロジェクトで VPC Service Controls が制限付きサービスに設定しているサービスを使用している場合(別のサービスから間接的に使用されるサービスも含む)、VPC Service Controls に起因する問題と考えられます。

既知の問題の事例については、サービスに関する既知の制限事項をご覧ください。

通常、サービスは依存関係に従ってエラー メッセージを伝播します。次のエラーのいずれかが発生した場合、VPC Service Controls に問題があります。

  • Cloud Storage: 403: Request violates VPC Service Controls.

  • BigQuery: 403: VPC Service Controls: Request is prohibited by organization's policy.

  • その他のサービス: 403: Request is prohibited by organization's policy.

VPC Service Controls が予期しない理由でブロックしたリクエストをデバッグする

VPC Service Controls がリクエストをブロックした理由を調査する場合、VPC Service Controls の監査ログが基本的なツールとなります。

通常、アクセスが予期せずにブロックされた場合は、プロジェクトの監査ログでリクエストの送信元を確認します。このログには、リクエストされたリソースやリクエストが拒否された理由に関する重要なデータが記録されています。

ログの詳細については、ログの表示をご覧ください。

次の表は、VPC Service Controls の使用時に発生する可能性のある violationReason の値を一覧にしたものです。

violationReason 説明
RESOURCES_NOT_IN_SAME_SERVICE_PERIMETER 監査ログレコードの resourceNames の下にあるリソースは、同じサービス境界内にありません。
NETWORK_NOT_IN_SAME_SERVICE_PERIMETER 監査ログレコードの callerNetworkresourceNames に対応するリソースは、同じサービス境界内にありません。
NO_MATCHING_ACCESS_LEVEL

監査ログレコード内の callerIp に対応する IP アドレスは、サービス境界に割り当てられたアクセスレベルの IP 範囲と一致しません。

サンプル事例

以下では、VPC Service Controls の使用中に発生する可能性があるシナリオについて説明します。

オンプレミスからの Cloud Storage へのアクセス

この例では、従業員のワークステーション(callerIp によって識別されたもの)からプロジェクト corp-storage の Cloud Storage バケットへのリクエストが、VPC Service Controls によってブロックされています。

このリクエストにより、次の監査ログレコードが生成されます。

{
 insertId:  "222lvajc6f7"
 logName:  "projects/corp-storage/logs/cloudaudit.googleapis.com%2Fpolicy"
 protoPayload: {
  @type:  "type.googleapis.com/google.cloud.audit.AuditLog"
  authenticationInfo: {
   principalEmail:  "someone@google.com"
  }
  metadata: {
   @type:  "type.googleapis.com/google.cloud.audit.VpcServiceControlAuditMetadata"
   resourceNames: [
    0:  "projects/_"
   ]
   violationReason:  "NO_MATCHING_ACCESS_LEVEL"
  }
  methodName:  "google.storage.NoBillingOk"
  requestMetadata: {
   callerIp:  "b1d5:d26d:5b17:43fe:d358:586b:db59:9617"
   destinationAttributes: {
   }
   requestAttributes: {
   }
  }
  resourceName:  "projects/690885588241"
  serviceName:  "storage.googleapis.com"
  status: {
   code:  7
   details: [
    0: {
     @type:  "type.googleapis.com/google.rpc.PreconditionFailure"
     violations: [
      0: {
       type:  "VPC_SERVICE_CONTROLS"
      }
     ]
    }
   ]
   message:  "Request is prohibited by organization's policy"
  }
 }
 receiveTimestamp:  "2018-11-27T21:40:43.823209571Z"
 resource: {
  labels: {
   method:  "google.storage.NoBillingOk"
   project_id:  "corp-storage"
   service:  "storage.googleapis.com"
  }
  type:  "audited_resource"
 }
 severity:  "ERROR"
 timestamp:  "2018-11-27T21:40:42.973784140Z"
}

corp-storage プロジェクトはサービス境界に含まれています。従業員のワークステーションは、境界内のネットワークに接続していません。従業員のワークステーションは境界の外側にあるため、リクエストがブロックされます。

プロジェクト外の VM から BigQuery へのアクセス

この例では、プロジェクト 458854174376data-collector)に属する VM が、プロジェクト 798816221974corp-resources-protected)内のデータセットに対して BigQuery クエリを実行しようとしますが、拒否されています。

VM は次のクエリを使用します。

bq --project=corp-resources-protected query 'select count(*) from babynames.yob2000'

クエリから次の結果が返されます。

BigQuery error in query operation: VPC Service Controls: Request is
prohibited by organization's policy. Operation ID:
33643962-6a0f-4091-9283-bcdf7e9271f0

次の監査ログレコードが生成されます。

{
 insertId:  "1ei551d2pdq"
 logName:  "projects/corp-resources-protected/logs/cloudaudit.googleapis.com%2Fpolicy"
 protoPayload: {
  @type:  "type.googleapis.com/google.cloud.audit.AuditLog"
  authenticationInfo: {
   principalEmail:  "714877721106-compute@example.gserviceaccount.com"
  }
  metadata: {
   @type:  "type.googleapis.com/google.cloud.audit.VpcServiceControlAuditMetadata"
   resourceNames: [
    0:  "projects/1004338142803"
   ]
   violationReason:  "NETWORK_NOT_IN_SAME_SERVICE_PERIMETER"
  }
  methodName:  "bigquery.googleapis.com/bigquery.jobs.create"
  requestMetadata: {
   callerIp:  "10.105.0.2"
   callerNetwork:  "//compute.googleapis.com/projects/ameet-dataflow/global/networks/__unknown__"
   destinationAttributes: {
   }
   requestAttributes: {
   }
  }
  resourceName:  "projects/1004338142803"
  serviceName:  "bigquery.googleapis.com"
  status: {
   code:  7
   details: [
    0: {
     @type:  "type.googleapis.com/google.rpc.PreconditionFailure"
     violations: [
      0: {
       type:  "VPC_SERVICE_CONTROLS"
      }
     ]
    }
   ]
   message:  "Request is prohibited by organization's policy"
  }
 }
 receiveTimestamp:  "2018-11-28T23:06:13.579882505Z"
 resource: {
  labels: {
   method:  "bigquery.googleapis.com/bigquery.jobs.create"
   project_id:  "corp-resources-protected"
   service:  "bigquery.googleapis.com"
  }
  type:  "audited_resource"
 }
 severity:  "ERROR"
 timestamp:  "2018-11-28T23:06:12.799656975Z"
}

この例では、violationReasonNETWORK_NOT_IN_SAME_SERVICE_PERIMETER です。callerIp の他に callerNetwork が含まれています。IP アドレスはプライベートであり、曖昧さを解消するためにネットワークが使用されています。ここで問題に関連するリソースが VpcServiceControlAuditMetadata.resourceNamesrequestMetadata.callerNetwork (ネットワークを所有するプロジェクト)の 2 つの場所に記録されています。

問題は、corp-resources-protected プロジェクトがサービス境界内にある一方、VM が所属するネットワークを含む data-collector プロジェクトが同じ境界内に存在していないことです。この場合、アクセスの拒否は想定どおりの結果です。

プロジェクト間の BigQuery クエリ

この例では、perimeter-network プロジェクトに属する VM が、perimeter-network と同じサービス境界内に存在するプロジェクト corp-resources-protected と、存在しないプロジェクト corp-resources-public の 2 つの異なるプロジェクトの BigQuery インスタンスにクエリを実行しようとしています。

VM は次のコマンドを使用します。

bq query --use_legacy_sql=false \
  'select count(priv.name),count(pub.name) from \
  `corp-resources-protected.babynames.yob2000` as priv, \
  `corp-resources-public.babynames.yob2000` as pub'

クエリから次の結果が返されます。

BigQuery error in query operation: Error processing job
'example:bqjob_r211e6f6eec928ffb_000001675c996aa8_1': VPC Service Controls:
Request is prohibited by organization's policy. Operation ID:
dc4fc177-4850-4fc5-b2e7-8c33f302149a

次の監査ログレコードが生成されます。

{
 insertId:  "17kg4exd24ag"
 logName:  "projects/perimeter-network/logs/cloudaudit.googleapis.com%2Fpolicy"
 protoPayload: {
  @type:  "type.googleapis.com/google.cloud.audit.AuditLog"
  authenticationInfo: {
  }
  metadata: {
   @type:  "type.googleapis.com/google.cloud.audit.VpcServiceControlAuditMetadata"
   resourceNames: [
    0:  "projects/117961063178"
    1:  "projects/690885588241"
   ]
   violationReason:  "RESOURCES_NOT_IN_SAME_SERVICE_PERIMETER"
  }
  methodName:  "bigquery.googleapis.com/bigquery.tables.getData"
  requestMetadata: {
   callerIp:  "130.211.225.66"
   callerNetwork:  "//compute.googleapis.com/projects/perimeter-network/global/networks/__unknown__"
   destinationAttributes: {
   }
   requestAttributes: {
   }
  }
  resourceName:  "projects/927005422713"
  serviceName:  "bigquery.googleapis.com"
  status: {
   code:  7
   details: [
    0: {
     @type:  "type.googleapis.com/google.rpc.PreconditionFailure"
     violations: [
      0: {
       type:  "VPC_SERVICE_CONTROLS"
      }
     ]
    }
   ]
   message:  "Request is prohibited by organization's policy"
  }
 }
 receiveTimestamp:  "2018-11-28T20:48:51.384237810Z"
 resource: {
  labels: {
   method:  "bigquery.googleapis.com/bigquery.tables.getData"
   project_id:  "perimeter-network"
   service:  "bigquery.googleapis.com"
  }
  type:  "audited_resource"
 }
 severity:  "ERROR"
 timestamp:  "2018-11-28T20:48:50.561884949Z"
}

callerNetworkVpcServiceControlAuditMetadata.resourceNames を見ると、perimeter-network117961063178corp-resources-public)、690885588241corp-resources-protected)の 3 つのプロジェクトが確認できます。corp-resources-public は、perimeter-networkcorp-resources-protected と同じサービス境界内に存在しないことを思い出してください。

violationReasonRESOURCES_NOT_IN_SAME_SERVICE_PERIMETER の場合、リクエストの一部のリソースが、リクエストに適用される境界の外側にあることを意味しています。この場合、corp-resources-public が境界外のリソースです。

境界内の VM から Cloud Storage へのファイルの移動

この例では、プロジェクト perimeter-network 内の VM がコマンドを使用して、プロジェクト corp-resources-protected にある 1 つの Cloud Storage バケットからプロジェクト corp-resources-public にある別のバケットにファイルを移動しようとしています。

VM は次のコマンドを使用します。

gsutil mv gs://corp-resources-private-1/yob2000.txt gs://corp-resources-public-1/babynames/

次の結果が返されます。

Copying gs://corp-resources-private-1/yob2000.txt [Content-Type=text/plain]...
AccessDeniedException: 403 Request violates VPC Service Controls.

次の監査ログレコードが生成されます。

{
 insertId:  "1xxnssmd2hqo"
 logName:  "projects/perimeter-network/logs/cloudaudit.googleapis.com%2Fpolicy"
 protoPayload: {
  @type:  "type.googleapis.com/google.cloud.audit.AuditLog"
  authenticationInfo: {
   principalEmail:  "storage-accessing@example.iam.gserviceaccount.com"
  }
  metadata: {
   @type:  "type.googleapis.com/google.cloud.audit.VpcServiceControlAuditMetadata"
   resourceNames: [
    0:  "projects/_/buckets/corp-resources-public-1"
   ]
   violationReason:  "NETWORK_NOT_IN_SAME_SERVICE_PERIMETER"
  }
  methodName:  "google.storage.BillingRequiredRead"
  requestMetadata: {
   callerIp:  "130.211.225.66"
   callerNetwork:  "//compute.googleapis.com/projects/perimeter-network/global/networks/__unknown__"
   destinationAttributes: {
   }
   requestAttributes: {
   }
  }
  resourceName:  "projects/927005422713"
  serviceName:  "storage.googleapis.com"
  status: {…}
 }
 receiveTimestamp:  "2018-11-28T00:45:31.531623485Z"
 resource: {
  labels: {
   method:  "google.storage.BillingRequiredRead"
   project_id:  "perimeter-network"
   service:  "storage.googleapis.com"
  }
  type:  "audited_resource"
 }
 severity:  "ERROR"
 timestamp:  "2018-11-28T00:45:31.351140381Z"
}

この場合、表示されたメソッドが BillingRequiredRead で、実行されたアクションが move のため、ログの内容が明確ではありません。これは、VPC Service Controls の現在の監査ログ機能の制限です。

理由は明確ではありませんが、この監査ログレコードは、リクエストの一部のリソースがリクエストに適用される境界の外側にあることを示しています。この場合、corp-resources-public が境界外のリソースです。

境界外の VM から Cloud Storage へのファイルの移動

この例では、プロジェクト public-network 内の VM がコマンドを使用して、プロジェクト corp-resources-protected にある 1 つの Cloud Storage バケットからプロジェクト corp-resources-public にある別のバケットにファイルを移動しようとしています。

corp-resources-protected はサービス境界によって保護されています。public-networkcorp-resources-public はこの境界の外側に存在しています。

VM は次のコマンドを使用します。

gsutil mv gs://corp-resources-private-1/yob2000.txt gs://corp-resources-public-1/babynames/

次の結果が返されます。

Copying gs://corp-resources-private-1/yob2000.txt [Content-Type=text/plain]...
AccessDeniedException: 403 Request violates VPC Service Controls.

次の監査ログレコードが生成されます。

{
 insertId:  "10moqhsch9v"
 logName:  "projects/corp-resources-private/logs/cloudaudit.googleapis.com%2Fpolicy"
 protoPayload: {
  @type:  "type.googleapis.com/google.cloud.audit.AuditLog"
  authenticationInfo: {
   principalEmail:  "user@example.biz"
  }
  metadata: {
   @type:  "type.googleapis.com/google.cloud.audit.VpcServiceControlAuditMetadata"
   resourceNames: [
    0:  "projects/_/buckets/corp-resources-private-1/objects/yob2000.txt"
    1:  "projects/_/buckets/corp-resources-public-1/objects/out.txt"
   ]
   violationReason:  "RESOURCES_NOT_IN_SAME_SERVICE_PERIMETER"
  }
  methodName:  "google.storage.Write"
  requestMetadata: {
   callerIp:  "2620:15c:2c4:203:63d6:5eb8:418d:c034"
   destinationAttributes: {
   }
   requestAttributes: {
   }
  }
  resourceName:  "projects/1004338142803"
  serviceName:  "storage.googleapis.com"
  status: {
   code:  7
   details: [
    0: {
     @type:  "type.googleapis.com/google.rpc.PreconditionFailure"
     violations: [
      0: {
       type:  "VPC_SERVICE_CONTROLS"
      }
     ]
    }
   ]
   message:  "Request is prohibited by organization's policy"
  }
 }
 receiveTimestamp:  "2018-11-30T16:34:46.948010626Z"
 resource: {
  labels: {
   method:  "google.storage.Write"
   project_id:  "corp-resources-private"
   service:  "storage.googleapis.com"
  }
  type:  "audited_resource"
 }
 severity:  "ERROR"
 timestamp:  "2018-11-30T16:34:46.898098978Z"
}

この例の監査ログは、サービス境界を越えてデータをコピーできないことを示しています(両方のリソースが監査ログレコードに記録されています)。リクエストが境界の外側(public-network の VM)から発生し、バケットの 1 つが境界(corp-resources-public-1)の外側に存在していることを思い出してください。

境界の外側から corp-resources-public-1 バケットへの書き込みはできるため、前の例で失敗したチェックはパスします。ただし、データを実際にコピーする際のチェックは失敗します。

この例でわかるように、ユーザーの 1 回の操作で複数の内部オペレーションが発生し、それぞれのオペレーションに VPC Service Controls のチェックが実行されます。

境界内の VM からの BigQuery データセットのコピー

この例では、プロジェクト 927005422713perimeter-network)の VM がプロジェクト corp-resources-private から corp-resources-public117961063178)に BigQuery データセットをコピーしようとしています。perimeter-networkcorp-resources-private は境界を共有する一方、corp-resources-public は境界の外側に存在します。

VM は次のコマンドを使用します。

bq cp corp-resources-private:babynames.yob2000 \
  corp-resources-public:babynames.yob2000

次の結果が返されます。

BigQuery error in cp operation: VPC Service Controls: Request is prohibited by
organization's policy. Operation ID: c00dbc44-460f-4bd0-9d09-cda98ac800f9

次の監査ログレコードが生成されます。

{
 insertId:  "146o5fd2hbp"
 logName:  "projects/perimeter-network/logs/cloudaudit.googleapis.com%2Fpolicy"
 protoPayload: {
  @type:  "type.googleapis.com/google.cloud.audit.AuditLog"
  authenticationInfo: {
  }
  metadata: {
   @type:  "type.googleapis.com/google.cloud.audit.VpcServiceControlAuditMetadata"
   resourceNames: [
    0:  "projects/117961063178"
   ]
   violationReason:  "RESOURCES_NOT_IN_SAME_SERVICE_PERIMETER"
  }
  methodName:  "bigquery.googleapis.com/bigquery.tables.get"
  requestMetadata: {
   callerIp:  "131.201.221.16"
   callerNetwork:  "//compute.googleapis.com/projects/perimeter-network/global/networks/__unknown__"
   destinationAttributes: {
   }
   requestAttributes: {
   }
  }
  resourceName:  "projects/927005422713"
  serviceName:  "bigquery.googleapis.com"
  status: {
   code:  7
   details: [
    0: {
     @type:  "type.googleapis.com/google.rpc.PreconditionFailure"
     violations: [
      0: {
       type:  "VPC_SERVICE_CONTROLS"
      }
     ]
    }
   ]
   message:  "Request is prohibited by organization's policy"
  }
 }
 receiveTimestamp:  "2018-11-28T00:27:05.688803777Z"
 resource: {
  labels: {
   method:  "bigquery.googleapis.com/bigquery.tables.get"
   project_id:  "perimeter-network"
   service:  "bigquery.googleapis.com"
  }
  type:  "audited_resource"
 }
 severity:  "ERROR"
 timestamp:  "2018-11-28T00:27:05.378584819Z"
}

この例では、ロギング メカニズムと BigQuery の分散アーキテクチャの制限により、1 つの API アクションで、このリクエストで使用されているすべてのリソースを確認することはできません。

監査ログレコードを見ると、データをコピーするために、BigQuery がプロジェクト perimeter-network(リクエストの送信元)のネットワークを使用してターゲット プロジェクト(corp-resources-public)にアクセスする必要があるため、オペレーションが失敗しています。corp-resources-public は、perimeter-network を保護する境界の外側にあることを思い出してください。このリクエストは、corp-resources-public にデータを抜き出そうとする試みとして拒否されます。

この例でもわかるように、データのコピーのような 1 つのオペレーションが、Cloud Storage、BigQuery、Bigtable など、さまざまなストレージ システムのデータにアクセスする複数の処理の引き金となる可能性があります。オペレーションの実行方法によっては、生成される監査ログレコードが元のユーザー コマンドと異なることがあります。特に、1 つのサービス内で複数のチェックが実行され、失敗した場合は結果が異なります。

プロジェクトからの Dataproc ジョブの読み込み

この例は、Dataproc などのデータ処理サービスの使用中に間接的に発生した VPC Service Controls のエラーをデバッグする方法を示しています。

この例では、VPC Service Controls で保護されたプロジェクトで Dataproc クラスタが稼働しています。Hello-world.py は、境界内の Cloud Storage バケットのデータにアクセスし、境界外の別のバケットに書き込む pyspark ジョブです。このオペレーションは、VPC Service Controls によってブロックされます。

Hello-world.py を実行するため、次のコマンドが使用されます。

gcloud dataproc jobs submit pyspark hello-world.py --cluster test-cluster-new2

次の結果が返されます。

Job [50f16ca8-5102-442b-a545-eed5e4f5f5da] submitted.
Waiting for job output...
18/11/29 00:31:34 INFO org.spark_project.jetty.util.log: Logging initialized @2552ms
18/11/29 00:31:34 INFO org.spark_project.jetty.server.Server: jetty-9.3.z-SNAPSHOT
18/11/29 00:31:34 INFO org.spark_project.jetty.server.Server: Started @2640ms
18/11/29 00:31:34 INFO org.spark_project.jetty.server.AbstractConnector: Started ServerConnector@1f1c18ec{HTTP/1.1,[http/1.1]}{0.0.0.0:4040}
18/11/29 00:31:34 INFO com.google.cloud.hadoop.fs.gcs.GoogleHadoopFileSystemBase: GHFS version: 1.6.4-hadoop2
18/11/29 00:31:35 INFO org.apache.hadoop.yarn.client.RMProxy: Connecting to ResourceManager at test-cluster-new2-m/10.246.0.3:8032
18/11/29 00:31:37 INFO org.apache.hadoop.yarn.client.api.impl.YarnClientImpl: Submitted application application_1522454176466_0005
Traceback (most recent call last):
  File "/tmp/50f16ca8-5102-442b-a545-eed5e4f5f5da/hello-world.py", line 8, in <module>
    lear.saveAsTextFile("gs://corp-resources-public-1/out.txt")
  File "/usr/lib/spark/python/lib/pyspark.zip/pyspark/rdd.py", line 1553, in saveAsTextFile
  File "/usr/lib/spark/python/lib/py4j-0.10.4-src.zip/py4j/java_gateway.py", line 1133, in __call__
  File "/usr/lib/spark/python/lib/py4j-0.10.4-src.zip/py4j/protocol.py", line 319, in get_return_value
py4j.protocol.Py4JJavaError: An error occurred while calling o49.saveAsTextFile.
: java.io.IOException: Error accessing: bucket: corp-resources-public-1, object: out.txt
    at com.google.cloud.hadoop.gcsio.GoogleCloudStorageImpl.wrapException(GoogleCloudStorageImpl.java:1767)
$sp(PairRDDFunctions.scala:961)

 (truncated)

Caused by: com.google.api.client.googleapis.json.GoogleJsonResponseException: 403 Forbidden
{
  "code" : 403,
  "errors" : [ {
    "domain" : "global",
    "message" : "Request violates VPC Service Controls.",
    "reason" : "vpcServiceControls"
  } ],
  "message" : "Request violates VPC Service Controls."
}
    at com.google.api.client.googleapis.json.GoogleJsonResponseException.from(GoogleJsonResponseException.java:145)

 (truncated)

18/11/29 00:31:43 INFO org.spark_project.jetty.server.AbstractConnector: Stopped Spark@1f1c18ec{HTTP/1.1,[http/1.1]}{0.0.0.0:4040}
ERROR: (gcloud.dataproc.jobs.submit.pyspark) Job [50f16ca8-5102-442b-a545-eed5e4f5f5da] entered state [ERROR] while waiting for [DONE].

saveAsTextFile が呼び出されたときに発生する IO 例外に注目してください。Cloud Storage によって、403 エラーとメッセージ Request violates VPC Service Controls が返されます。このエラーは、Cloud Storage 監査ログのオペレーションを確認する必要があることを示しています。

コマンドが実行された perimeter-network プロジェクトの監査ログには、saveAsTextFile オペレーションの監査ログレコードがあります。

{
 insertId:  "qdj1o9d1run"
 logName:  "projects/corp-resources-private/logs/cloudaudit.googleapis.com%2Fpolicy"
 protoPayload: {
  @type:  "type.googleapis.com/google.cloud.audit.AuditLog"
  authenticationInfo: {
   principalEmail:  "1004338142803-compute@example.gserviceaccount.com"
  }
  metadata: {
   @type:  "type.googleapis.com/google.cloud.audit.VpcServiceControlAuditMetadata"
   resourceNames: [
    0:  "projects/_/buckets/corp-resources-public-1/objects/out.txt"
   ]
   violationReason:  "RESOURCES_NOT_IN_SAME_SERVICE_PERIMETER"
  }
  methodName:  "google.storage.BillingRequiredRead"
  requestMetadata: {
   callerIp:  "10.246.0.3"
   callerNetwork:  "//compute.googleapis.com/projects/corp-resources-private/global/networks/__unknown__"
   destinationAttributes: {
   }
   requestAttributes: {
   }
  }
  resourceName:  "projects/1004338142803"
  serviceName:  "storage.googleapis.com"
  status: {
   code:  7
   details: [
    0: {
     @type:  "type.googleapis.com/google.rpc.PreconditionFailure"
     violations: [
      0: {
       type:  "VPC_SERVICE_CONTROLS"
      }
     ]
    }
   ]
   message:  "Request is prohibited by organization's policy"
  }
 }
 receiveTimestamp:  "2018-11-29T00:31:43.666227930Z"
 resource: {
  labels: {
   method:  "google.storage.BillingRequiredRead"
   project_id:  "corp-resources-private"
   service:  "storage.googleapis.com"
  }
  type:  "audited_resource"
 }
 severity:  "ERROR"
 timestamp:  "2018-11-29T00:31:43.608250320Z"
}

監査ログの制限により、実際のオペレーションが write であっても、Cloud Storage の methodNameRead と表示されます。監査ログレコードを見ると、プロジェクト corp-resources-private 内のネットワークがバケット corp-resources-public-1 のリソースのデータにアクセスを試みたため(この場合は書き込み)、オペレーションが失敗しています。Cloud Storage の監査ログに制限があるため、プロジェクト バケット corp-resources-public-1 の所属先がわかりません。

corp-resources-public-1 を含むプロジェクトを特定するには、次のコマンドを使用します。

gsutil --debug ls -L -b gs://corp-resources-public-1 2>&1 | grep projectNumber

次の結果が返されます。

projectNumber: u'117961063178'

117961063178 はプロジェクト corp-resources-public で、これは境界外にあります。つまり、このエラーは予想されたものです。

制限付き VIP でサポートされていないサービス

VPC Service Controls の制限付き VIP でサポートされていない API にアクセスを試みると、404 エラーが発生します。たとえば、Cloud DNS は現在 VPC Service Controls でサポートされていないため、制限付き VIP を使用している場合は Cloud DNS API を使用できません。

たとえば、次のコマンドを使用したとします。

gcloud dns managed-zones list

次の結果が返されます。

ERROR: (gcloud.dns.managed-zones.list) Project [corp-resources-private] not found: <!DOCTYPE html>
<html lang=en>
  <meta charset=utf-8>
  <meta name=viewport content="initial-scale=1, minimum-scale=1, width=device-width">
  <title>Error 404 (Not Found)!!1</title>
  <style>
    *{margin:0;padding:0}html,code{font:15px/22px arial,sans-serif}html{background:#fff;color:#222;padding:15px}body{margin:7% auto 0;max-width:390px;min-height:180px;padding:30px 0 15px}* > body{background:url(//www.google.com/images/errors/robot.png) 100% 5px no-repeat;padding-right:205px}p{margin:11px 0 22px;overflow:hidden}ins{color:#777;text-decoration:none}a img{border:0}@media screen and (max-width:772px){body{background:none;margin-top:0;max-width:none;padding-right:0}}#logo{background:url(//www.google.com/images/branding/googlelogo/1x/googlelogo_color_150x54dp.png) no-repeat;margin-left:-5px}@media only screen and (min-resolution:192dpi){ #logo{background:url(//www.google.com/images/branding/googlelogo/2x/googlelogo_color_150x54dp.png) no-repeat 0% 0%/100% 100%;-moz-border-image:url(//www.google.com/images/branding/googlelogo/2x/googlelogo_color_150x54dp.png) 0}}@media only screen and (-webkit-min-device-pixel-ratio:2){ #logo{background:url(//www.google.com/images/branding/googlelogo/2x/googlelogo_color_150x54dp.png) no-repeat;-webkit-background-size:100% 100%}}#logo{display:inline-block;height:54px;width:150px}
  </style>
  <a href=//www.google.com/><span id=logo aria-label=Google></span></a>
  <p><b>404.</b> <ins>That's an error.</ins>
  <p>The requested URL <code>/dns/v1/projects/corp-resources-private/managedZones</code> was not found on this server.  <ins>That's all we know.</ins>

VPC Service Controls でサポートされず、制限付き VIP で使用できないサービスの場合、このタイプのエラーは予想されるエラーです。このエラーが VPC Service Controls でサポートされているサービスで発生した場合は、そのサービスを既知の制限事項で調べて、サービスが既知の制限事項に該当するかどうか確認してください。該当していない場合は、問題を報告する必要があります

境界外のプロジェクトへのログのエクスポート

この例では、ログのエクスポートが VPC Service Controls でブロックされています。エクスポート先のプロジェクト corp-resources-public は VPC Service Controls の境界外にある一方、シンクはプロジェクト perimeter-network に作成されますが、このプロジェクトは境界内にあります。

たとえば、次のコマンドを使用したとします。

gcloud logging sinks describe example-sink

次の結果が返されます。

destination: bigquery.googleapis.com/projects/corp-resources-public/datasets/logs
filter: |-
  resource.type="audited_resource"
  resource.labels.service="bigquery.googleapis.com"
name: example-sink
outputVersionFormat: V2
writerIdentity: serviceAccount:p927005422713-439672@gcp-sa-logging.iam.gserviceaccount.com

次の監査ログレコードが生成されます。

{
 insertId:  "e5i2i8cbqw"
 logName:  "projects/perimeter-network/logs/cloudaudit.googleapis.com%2Fpolicy"
 protoPayload: {
  @type:  "type.googleapis.com/google.cloud.audit.AuditLog"
  authenticationInfo: {
   principalEmail:  "p927005422713-439672@gcp-sa-logging.iam.gserviceaccount.com"
  }
  metadata: {
   @type:  "type.googleapis.com/google.cloud.audit.VpcServiceControlAuditMetadata"
   resourceNames: [
    0:  "corp-resources-public"
   ]
   violationReason:  "RESOURCES_NOT_IN_SAME_SERVICE_PERIMETER"
  }
  methodName:  "google.cloud.bigquery.v2.TableDataService.InsertAll"
  requestMetadata: {
   callerIp:  "2002:a49:8c51::"
   destinationAttributes: {
   }
   requestAttributes: {
   }
  }
  resourceName:  "projects/927005422713"
  serviceName:  "bigquery.googleapis.com"
  status: {
   code:  7
   details: [
    0: {
     @type:  "type.googleapis.com/google.rpc.PreconditionFailure"
     violations: [
      0: {
       type:  "VPC_SERVICE_CONTROLS"
      }
     ]
    }
   ]
   message:  "Request is prohibited by organization's policy"
  }
 }
 receiveTimestamp:  "2018-11-29T17:32:19.287138882Z"
 resource: {
  labels: {
   method:  "google.cloud.bigquery.v2.TableDataService.InsertAll"
   project_id:  "perimeter-network"
   service:  "bigquery.googleapis.com"
  }
  type:  "audited_resource"
 }
 severity:  "ERROR"
 timestamp:  "2018-11-29T17:32:19.054662413Z"
}

監査ログレコードは、Logging ではなく BigQuery に対して生成されます。これは、Logging が書き込むシンクサービスが BigQuery のためです。

corp-resources-public がプロジェクト perimeter-network を保護する境界の外側に存在するため、エクスポートが失敗します。

この例で示すように、Google Cloud サービスが p927005422713-439672@gcp-sa-logging.iam.gserviceaccount.com のような内部と GCP 間のマネージド サービス アカウントを使用して別のサービスを呼び出す場合、リクエストのネットワーク プロジェクト(この場合は perimeter-network)はその ID から派生します。ログ エクスポートのリソースも同じ ID で表されます。

これは Google Cloud では一般的なパターンで、サービス間のやり取りの多くで行われています。

Cloud Storage への BigQuery の抽出

この例では、失敗した BigQuery から Cloud Storage への抽出をデバッグする方法について説明します。

この例では、corp-resources-privateperimeter-network がサービス境界で保護されたプロジェクトです。corp-resources-public は境界外にあるプロジェクトです。

次のコマンドを使用したとします。

bq extract babynames.yob2000

次の結果が返されます。

gs://corp-resources-public-1/export.txt
Waiting on bqjob_r47ee34109d02b41_000001676b27157c_1 ... (1s) Current status: DONE
BigQuery error in extract operation: Error processing job 'corp-resources-private:bqjob_r47ee34109d02b41_000001676b27157c_1': Access
Denied: BigQuery BigQuery: Permission denied while writing data.

このエラーは、VPC Service Controls に固有のものではありません。Identity and Access Management の障害の場合でも同様のエラーが発生します。

次の監査ログレコードが生成されます。

{
 insertId:  "4gbh6pe8jld7"
 logName:  "projects/corp-resources-private/logs/cloudaudit.googleapis.com%2Fdata_access"
 protoPayload: {
  @type:  "type.googleapis.com/google.cloud.audit.AuditLog"
  authenticationInfo: {
   principalEmail:  "storage-accessing@example.iam.gserviceaccount.com"
  }
  methodName:  "jobservice.jobcompleted"
  requestMetadata: {
   callerIp:  "10.5.0.4"
   callerNetwork:  "//compute.googleapis.com/projects/perimeter-network/global/networks/__unknown__"
   callerSuppliedUserAgent:  "google-api-python-client/1.6.5 (gzip),gzip(gfe)"
   destinationAttributes: {
   }
   requestAttributes: {
   }
  }
  resourceName:  "projects/corp-resources-private/jobs/bqjob_r47ee34109d02b41_000001676b27157c_1"
  serviceData: {
   @type:  "type.googleapis.com/google.cloud.bigquery.logging.v1.AuditData"
   jobCompletedEvent: {
    eventName:  "extract_job_completed"
    job: {
     jobConfiguration: {
      extract: {
       destinationUris: [
        0:  "gs://corp-resources-public-1/export.txt"
       ]
       sourceTable: {
        datasetId:  "babynames"
        projectId:  "corp-resources-private"
        tableId:  "yob2000"
       }
      }
     }
     jobName: {
      jobId:  "bqjob_r47ee34109d02b41_000001676b27157c_1"
      location:  "US"
      projectId:  "corp-resources-private"
     }
     jobStatistics: {
      createTime:  "2018-12-01T19:03:03.908Z"
      endTime:  "2018-12-01T19:03:05.494Z"
      startTime:  "2018-12-01T19:03:04.013Z"
     }
     jobStatus: {
      additionalErrors: [
       0: {
        code:  7
        message:  "Access Denied: BigQuery BigQuery: Permission denied while writing data."
       }
      ]
      error: {
       code:  7
       message:  "Access Denied: BigQuery BigQuery: Permission denied while writing data."
      }
      state:  "DONE"
     }
    }
   }
  }
  serviceName:  "bigquery.googleapis.com"
  status: {
   code:  7
   message:  "Access Denied: BigQuery BigQuery: Permission denied while writing data."
  }
 }
 receiveTimestamp:  "2018-12-01T19:03:05.532169998Z"
 resource: {
  labels: {
   project_id:  "corp-resources-private"
  }
  type:  "bigquery_resource"
 }
 severity:  "ERROR"
 timestamp:  "2018-12-01T19:03:05.503Z"
}

この監査ログレコードで、storage-accessing@example.iam.gserviceaccount.com はオペレーションの実行を試みた ID です。この例では、コマンドの実行に必要な IAM 権限が storage-accessing@example.iam.gserviceaccount.com にあるとします。

IAM 権限は原因ではないため、次に VPC Service Controls のエラーかどうかを確認します。

宛先のサービス(Cloud Storage)の監査ログレコードに、詳しい失敗理由が記録されています。

{
 insertId:  "1bq397kcfj1"
 logName:  "projects/corp-resources-private/logs/cloudaudit.googleapis.com%2Fpolicy"
 protoPayload: {
  @type:  "type.googleapis.com/google.cloud.audit.AuditLog"
  authenticationInfo: {
   principalEmail:  "storage-accessing@example.iam.gserviceaccount.com"
  }
  metadata: {
   @type:  "type.googleapis.com/google.cloud.audit.VpcServiceControlAuditMetadata"
   resourceNames: [
    0:  "projects/1004338142803"
    1:  "projects/_/buckets/corp-resources-public-1"
   ]
   violationReason:  "RESOURCES_NOT_IN_SAME_SERVICE_PERIMETER"
  }
  methodName:  "google.storage.BillingRequiredRead"
  requestMetadata: {
   callerIp:  "10.5.0.4"
   callerNetwork:  "//compute.googleapis.com/projects/perimeter-network/global/networks/__unknown__"
   destinationAttributes: {
   }
   requestAttributes: {
   }
  }
  resourceName:  "projects/1004338142803"
  serviceName:  "storage.googleapis.com"
  status: {
   code:  7
   details: [
    0: {
     @type:  "type.googleapis.com/google.rpc.PreconditionFailure"
     violations: [
      0: {
       type:  "VPC_SERVICE_CONTROLS"
      }
     ]
    }
   ]
   message:  "Request is prohibited by organization's policy"
  }
 }
 receiveTimestamp:  "2018-12-01T19:03:05.617451586Z"
 resource: {
  labels: {
   method:  "google.storage.BillingRequiredRead"
   project_id:  "corp-resources-private"
   service:  "storage.googleapis.com"
  }
  type:  "audited_resource"
 }
 severity:  "ERROR"
 timestamp:  "2018-12-01T19:03:05.420005215Z"
}

このログを見ると、コマンドを完了するために、2 つのプロジェクト 1004338142803corp-resources-private-1)と corp-resources-public が使用されていることがわかります。これらのプロジェクトは境界を共有していないため、抽出ジョブが失敗しています。

この例が示しているように、複雑なマルチサービス オペレーションの場合、元のサービスと宛先のサービスの両方の監査ログに、デバッグに役立つデータが記録されている可能性があります。