Skip to content

Commit

Permalink
add occurrence
Browse files Browse the repository at this point in the history
  • Loading branch information
emilymye committed May 26, 2020
1 parent 59f5fc3 commit 26e0316
Show file tree
Hide file tree
Showing 10 changed files with 656 additions and 64 deletions.
113 changes: 112 additions & 1 deletion products/containeranalysis/api.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,12 @@ objects:
update_verb: :PATCH
update_mask: true
description: |
A Container Analysis note is a high-level piece of metadata that
A Container Analysis note is a high-level piece of metadata that
describes a type of analysis that can be done for a resource.
references: !ruby/object:Api::Resource::ReferenceLinks
guides:
'Official Documentation': 'https://cloud.google.com/container-analysis/'
'Creating Attestations (Occurrences)': 'https://cloud.google.com/binary-authorization/docs/making-attestations'
api: 'https://cloud.google.com/container-analysis/api/reference/rest/'
properties:
- !ruby/object:Api::Type::String
Expand Down Expand Up @@ -132,3 +133,113 @@ objects:
The human readable name of this Attestation Authority, for
example "qa".
required: true

- !ruby/object:Api::Resource
name: 'Occurrence'
base_url: projects/{{project}}/occurrences
self_link: projects/{{project}}/occurrences/{{name}}
update_verb: :PATCH
update_mask: true
description: |
An occurrence is an instance of a Note, or type of analysis that
can be done for a resource.
references: !ruby/object:Api::Resource::ReferenceLinks
guides:
'Official Documentation': 'https://cloud.google.com/container-analysis/'
api: 'https://cloud.google.com/container-analysis/api/reference/rest/'
properties:
- !ruby/object:Api::Type::String
name: name
description: |
The name of the occurrence.
output: true
- !ruby/object:Api::Type::String
name: resourceUri
description: |
Required. Immutable. A URI that represents the resource for which
the occurrence applies. For example,
https://gcr.io/project/image@sha256:123abc for a Docker image.
required: true
input: true
- !ruby/object:Api::Type::String
name: noteName
description: |
The analysis note associated with this occurrence, in the form of
projects/[PROVIDER_ID]/notes/[NOTE_ID]. This field can be used as a
filter in list requests.
required: true
input: true
- !ruby/object:Api::Type::String
name: kind
description: |
The note kind which explicitly denotes which of the occurrence
details are specified. This field can be used as a filter in list
requests.
output: true
- !ruby/object:Api::Type::String
name: remediation
description: |
A description of actions that can be taken to remedy the note.
- !ruby/object:Api::Type::Time
name: createTime
description: The time when the repository was created.
output: true
- !ruby/object:Api::Type::Time
name: updateTime
description: The time when the repository was last updated.
output: true
- !ruby/object:Api::Type::NestedObject
name: attestation
description: |
Occurrence that represents a single "attestation". The authenticity
of an attestation can be verified using the attached signature.
If the verifier trusts the public key of the signer, then verifying
the signature is sufficient to establish trust. In this circumstance,
the authority to which this attestation is attached is primarily
useful for lookup (how to find this attestation if you already
know the authority and artifact to be verified) and intent (for
which authority this attestation was intended to sign.
required: true
properties:
- !ruby/object:Api::Type::String
name: serializedPayload
description: |
The serialized payload that is verified by one or
more signatures. A base64-encoded string.
required: true
- !ruby/object:Api::Type::Array
name: signatures
description: |
One or more signatures over serializedPayload.
Verifier implementations should consider this attestation
message verified if at least one signature verifies
serializedPayload. See Signature in common.proto for more
details on signature structure and verification.
required: true
item_type: !ruby/object:Api::Type::NestedObject
properties:
- !ruby/object:Api::Type::String
name: signature
description: |
The content of the signature, an opaque bytestring.
The payload that this signature verifies MUST be
unambiguously provided with the Signature during
verification. A wrapper message might provide the
payload explicitly. Alternatively, a message might
have a canonical serialization that can always be
unambiguously computed to derive the payload.
- !ruby/object:Api::Type::String
name: publicKeyId
required: true
description: |
The identifier for the public key that verifies this
signature. The publicKeyId MUST be an RFC3986 conformant
URI. * When possible, the publicKeyId SHOULD be an
immutable reference, such as a cryptographic digest.
Examples of valid publicKeyIds:
* OpenPGP V4 public key fingerprint. See https://www.iana.org/assignments/uri-schemes/prov/openpgp4fpr
for more details on this scheme.
* `openpgp4fpr:74FAF3B861BDA0870C7B6DEF607E48D2A663AEEA`
* RFC6920 digest-named SubjectPublicKeyInfo (digest of the DER serialization):
* "ni:///sha-256;cD9o9Cq6LG3jD0iKXqEi_vdjJGecm_iXkbqVoScViaU"
25 changes: 24 additions & 1 deletion products/containeranalysis/terraform.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,10 @@
--- !ruby/object:Provider::Terraform::Config
overrides: !ruby/object:Overrides::ResourceOverrides
Note: !ruby/object:Overrides::Terraform::ResourceOverride
mutex: "projects/{{project}}/notes/{{name}}"
id_format: "projects/{{project}}/notes/{{name}}"
import_format: ["projects/{{project}}/notes/{{name}}"]
custom_code: !ruby/object:Provider::Terraform::CustomCode
# pre_update: 'templates/terraform/pre_update/containeranalysis_note.erb'
encoder: templates/terraform/encoders/containeranalysis_attestation_field_name.go.erb
decoder: templates/terraform/decoders/containeranalysis_attestation_field_name.go.erb
examples:
Expand All @@ -38,6 +38,29 @@ overrides: !ruby/object:Overrides::ResourceOverrides
is_set: true
relatedNoteNames: !ruby/object:Overrides::Terraform::PropertyOverride
is_set: true
Occurrence: !ruby/object:Overrides::Terraform::ResourceOverride
# "projects/{{project}}/notes/{{name}}"
mutex: "{{note_name}}"
id_format: "projects/{{project}}/occurrences/{{name}}"
import_format: ["projects/{{project}}/occurrences/{{name}}"]
examples:
- !ruby/object:Provider::Terraform::Examples
name: "container_analysis_occurrence_kms"
# Occurrence requires custom logic for signing payloads.
skip_test: true
primary_resource_id: "occurrence"
vars:
note_name: "attestation-note"
attestor: "attestor"
custom_code: !ruby/object:Provider::Terraform::CustomCode
encoder: templates/terraform/encoders/containeranalysis_occurrence.go.erb
update_encoder: templates/terraform/update_encoder/containeranalysis_occurrence.go.erb
decoder: templates/terraform/decoders/containeranalysis_occurrence.go.erb
properties:
name: !ruby/object:Overrides::Terraform::PropertyOverride
custom_flatten: templates/terraform/custom_flatten/name_from_self_link.erb
attestation.signatures: !ruby/object:Overrides::Terraform::PropertyOverride
is_set: true

# This is for copying files over
files: !ruby/object:Provider::Config::Files
Expand Down
43 changes: 43 additions & 0 deletions templates/terraform/decoders/containeranalysis_occurrence.go.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<%# The license inside this block applies to this file.
# Copyright 2020 Google Inc.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
-%>
<% unless version == 'ga' -%>
// Resource object was flattened in GA API
if nestedResource, ok := res["resource"]; ok {
if resObj, ok := nestedResource.(map[string]interface{}); ok {
res["resourceUri"] = resObj["uri"]
delete(res, "resource")
}
}

// Beta attestation.attestation.genericSignedAttestation
// => GA attestation
if attV, ok := res["attestation"]; ok && attV != nil {
att := attV.(map[string]interface{})
if nestedAttV, ok := att["attestation"]; ok && nestedAttV != nil {
nestedAtt := nestedAttV.(map[string]interface{})
if genericV, ok := nestedAtt["genericSignedAttestation"]; ok {
genericAtt := genericV.(map[string]interface{})
res["attestation"] = map[string]interface{}{
"serializedPayload": genericAtt["serializedPayload"],
"signatures": genericAtt["signatures"],
}
}
}
}

<% else -%>
// encoder logic only in non-GA version
<% end -%>
return res, nil
43 changes: 43 additions & 0 deletions templates/terraform/encoders/containeranalysis_occurrence.go.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<%# The license inside this block applies to this file.
# Copyright 2020 Google Inc.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
-%>
<% unless version == 'ga' -%>
// Resource object was flattened in GA API
if resourceuri, ok := obj["resourceUri"]; ok {
obj["resource"] = map[string]interface{}{
"uri": resourceuri,
}
delete(obj, "resourceUri")
}


// Beta `attestation.genericSignedAttestation` was flattened to just
// `attestation` (no contentType) in GA
if v, ok := obj["attestation"]; ok && v != nil {
gaAtt := v.(map[string]interface{})
obj["attestation"] = map[string]interface{}{
"attestation": map[string]interface{}{
"genericSignedAttestation": map[string]interface{}{
"contentType": "SIMPLE_SIGNING_JSON",
"serializedPayload": gaAtt["serializedPayload"],
"signatures": gaAtt["signatures"],
},
},
}
}
<% else -%>
// encoder logic only in non-GA versions
<% end -%>

return obj, nil
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
resource "google_binary_authorization_attestor" "<%= ctx[:primary_resource_id] %>" {
name = "<%= ctx[:vars]["attestor_name"] %>"
attestation_authority_note {
note_reference = google_container_analysis_note.note.name
public_keys {
ascii_armored_pgp_public_key = <<EOF
mQENBFtP0doBCADF+joTiXWKVuP8kJt3fgpBSjT9h8ezMfKA4aXZctYLx5wslWQl
bB7Iu2ezkECNzoEeU7WxUe8a61pMCh9cisS9H5mB2K2uM4Jnf8tgFeXn3akJDVo0
oR1IC+Dp9mXbRSK3MAvKkOwWlG99sx3uEdvmeBRHBOO+grchLx24EThXFOyP9Fk6
V39j6xMjw4aggLD15B4V0v9JqBDdJiIYFzszZDL6pJwZrzcP0z8JO4rTZd+f64bD
Mpj52j/pQfA8lZHOaAgb1OrthLdMrBAjoDjArV4Ek7vSbrcgYWcI6BhsQrFoxKdX
83TZKai55ZCfCLIskwUIzA1NLVwyzCS+fSN/ABEBAAG0KCJUZXN0IEF0dGVzdG9y
IiA8ZGFuYWhvZmZtYW5AZ29vZ2xlLmNvbT6JAU4EEwEIADgWIQRfWkqHt6hpTA1L
uY060eeM4dc66AUCW0/R2gIbLwULCQgHAgYVCgkICwIEFgIDAQIeAQIXgAAKCRA6
0eeM4dc66HdpCAC4ot3b0OyxPb0Ip+WT2U0PbpTBPJklesuwpIrM4Lh0N+1nVRLC
51WSmVbM8BiAFhLbN9LpdHhds1kUrHF7+wWAjdR8sqAj9otc6HGRM/3qfa2qgh+U
WTEk/3us/rYSi7T7TkMuutRMIa1IkR13uKiW56csEMnbOQpn9rDqwIr5R8nlZP5h
MAU9vdm1DIv567meMqTaVZgR3w7bck2P49AO8lO5ERFpVkErtu/98y+rUy9d789l
+OPuS1NGnxI1YKsNaWJF4uJVuvQuZ1twrhCbGNtVorO2U12+cEq+YtUxj7kmdOC1
qoIRW6y0+UlAc+MbqfL0ziHDOAmcqz1GnROg
=6Bvm
EOF

}
}
}

resource "google_container_analysis_note" "note" {
name = "<%= ctx[:vars]["note_name"] %>"
attestation_authority {
hint {
human_readable_name = "Attestor Note"
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
resource "google_binary_authorization_attestor" "attestor" {
name = "<%= ctx[:vars]["attestor"] %>"
attestation_authority_note {
note_reference = google_container_analysis_note.note.name
public_keys {
id = data.google_kms_crypto_key_version.version.id
pkix_public_key {
public_key_pem = data.google_kms_crypto_key_version.version.public_key[0].pem
signature_algorithm = data.google_kms_crypto_key_version.version.public_key[0].algorithm
}
}
}
}

resource "google_container_analysis_note" "note" {
name = "<%= ctx[:vars]["note_name"] %>"
attestation_authority {
hint {
human_readable_name = "Attestor Note"
}
}
}

data "google_kms_key_ring" "keyring" {
name = "my-key-ring"
location = "global"
}

data "google_kms_crypto_key" "crypto-key" {
name = "my-key"
key_ring = data.google_kms_key_ring.keyring.self_link
}

data "google_kms_crypto_key_version" "version" {
crypto_key = data.google_kms_crypto_key.crypto-key.self_link
}

resource "google_container_analysis_occurrence" "<%= ctx[:primary_resource_id] %>" {
resource_uri = "gcr.io/my-project/my-image"
note_name = google_container_analysis_note.note.id

// See "Creating Attestations" Guide for expected
// payload and signature formats.
attestation {
serialized_payload = filebase64("path/to/my/payload.json")
signatures {
public_key_id = data.google_kms_crypto_key_version.version.id
serialized_payload = filebase64("path/to/my/payload.json.sig")
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<%# The license inside this block applies to this file.
# Copyright 2020 Google Inc.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
-%>
// Note is required, even for PATCH
noteNameProp, err := expandContainerAnalysisOccurrenceNoteName(d.Get("note_name"), d, meta.(*Config))
if err != nil {
return nil, err
} else if v, ok := d.GetOkExists("note_name"); !isEmptyValue(reflect.ValueOf(noteNameProp)) && (ok || !reflect.DeepEqual(v, noteNameProp)) {
obj["noteName"] = noteNameProp
}

return resource<%= resource_name -%>Encoder(d, meta, obj)
Loading

0 comments on commit 26e0316

Please sign in to comment.