Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support containeranalysis Note and Occurence for attestation #3564

Merged
merged 3 commits into from
May 27, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
170 changes: 169 additions & 1 deletion products/containeranalysis/api.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,14 @@ objects:
base_url: projects/{{project}}/notes?noteId={{name}}
self_link: projects/{{project}}/notes/{{name}}
update_verb: :PATCH
update_mask: true
description: |
Provides a detailed description of a Note.
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 All @@ -42,6 +45,61 @@ objects:
The name of the note.
required: true
input: true
- !ruby/object:Api::Type::String
name: shortDescription
description: |
A one sentence description of the note.
- !ruby/object:Api::Type::String
name: longDescription
description: |
A detailed description of the note
- !ruby/object:Api::Type::Enum
name: 'kind'
description: |
The type of analysis this note describes
values:
- NOTE_KIND_UNSPECIFIED
- VULNERABILITY
- BUILD
- IMAGE
- PACKAGE
- DEPLOYMENT
- DISCOVERY
- ATTESTATION
- UPGRADE
output: true
- !ruby/object:Api::Type::Array
name: relatedUrl
description: |
URLs associated with this note and related metadata.
item_type: !ruby/object:Api::Type::NestedObject
properties:
- !ruby/object:Api::Type::String
name: url
description: |
Specific URL associated with the resource.
required: true
- !ruby/object:Api::Type::String
name: label
description: |
Label to describe usage of the URL
- !ruby/object:Api::Type::Time
name: expirationTime
description: |
Time of expiration for this note. Leave empty if note does not expire.
- !ruby/object:Api::Type::Time
name: createTime
description: The time this note was created.
output: true
- !ruby/object:Api::Type::Time
name: updateTime
description: The time this note was last updated.
output: true
- !ruby/object:Api::Type::Array
name: relatedNoteNames
description: |
Names of other notes related to this note.
item_type: Api::Type::String
- !ruby/object:Api::Type::NestedObject
name: attestationAuthority
description: |
Expand Down Expand Up @@ -75,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
slevenick marked this conversation as resolved.
Show resolved Hide resolved
description: |
The analysis note associated with this occurrence, in the form of
projects/[PROJECT]/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
slevenick marked this conversation as resolved.
Show resolved Hide resolved
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. MUST be an RFC3986 conformant
URI. * When possible, the key id should be an
immutable reference, such as a cryptographic digest.
Examples of valid values:

* 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"
36 changes: 34 additions & 2 deletions products/containeranalysis/terraform.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,21 +14,53 @@
--- !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:
- !ruby/object:Provider::Terraform::Examples
name: "container_analysis_note_basic"
primary_resource_id: "note"
vars:
note_name: "test-attestor-note"
note_name: "attestor-note"
- !ruby/object:Provider::Terraform::Examples
name: "container_analysis_note_attestation_full"
primary_resource_id: "note"
vars:
note_name: "attestor-note"
properties:
name: !ruby/object:Overrides::Terraform::PropertyOverride
custom_flatten: 'templates/terraform/custom_flatten/name_from_self_link.erb'
relatedUrl: !ruby/object:Overrides::Terraform::PropertyOverride
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,22 @@
resource "google_container_analysis_note" "<%= ctx[:primary_resource_id] %>" {
name = "<%= ctx[:vars]["note_name"] %>"

short_description = "test note"
long_description = "a longer description of test note"
expiration_time = "2120-10-02T15:01:23.045123456Z"

related_url {
url = "some.url"
label = "foo"
}

related_url {
url = "google.com"
}

attestation_authority {
hint {
human_readable_name = "Attestor Note"
}
}
}
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"
}
}
}
Loading