Skip to content
Open
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
4 changes: 2 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,13 @@ RUN go mod download

COPY . .

RUN go build -o provider provider.go
RUN go build -o provider .

FROM $BASEIMAGE

WORKDIR /

COPY --from=builder /go/src/github.com/developer-guy/cosign-gatekeeper-provider .
COPY --from=builder /go/src/github.com/developer-guy/cosign-gatekeeper-provider/provider .

USER 65532:65532

Expand Down
121 changes: 114 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,19 +28,126 @@ Let's install the `cosign-gatekeeper-provider`:

## Verification

To test this successfully, we should sign one of our images with [cosign](https://github.com/sigstore/cosign#installation) tool. So, let's do this first:

Generate key pair
```shell
$ cosign generate-key-pair
```
To test this successfully, we should sign one of our images with [cosign](https://github.com/sigstore/cosign#installation) tool.

We have two files under `policy/examples`, one for valid manifest that contains signed image, the other is invalid. To do the same you should sign your image as I did:

```shell
$ crane copy alpine:latest devopps/alpine:signed
$ crane copy alpine:3.14 devopps/alpine:unsigned
$ cosign sign --key cosign.key devopps/signed:latest
$ COSIGN_EXPERIMENTAL=1 cosign sign devopps/signed:latest
```

So, once you are ready, let's apply these manifests one by one. It should allow deploying Pod for valid.yaml, and deny for the other one.

## Configuration

By default, the provider verifies images against `https://rekor.sigstore.dev`
with the Fulcio roots.

You can configure the list of verifiers by passing a configuration file with
the `-config-file=<file>` flag.

For example:

```yaml
verifiers:
- options:
key: "gcpkms://projects/my-project/locations/global/keyRings/my-keyring/cryptoKeys/my-key"

- options:
key: "/cosign.pub"

- options:
key: |-
-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAERe5B6LSgARjUVg4TwTwhlcUP0+pC
hunFRFW/e35eK5KQ3ju6yJpVuypEqVvkD5sIRoTyQeTbkk1QVvJHZ2aDXQ==
-----END PUBLIC KEY-----

# Your own rekor server. The root certificates can also be configured with
# the SIGSTORE_ROOT_FILE environment variable.
- options:
rekorURL: "https://rekor.my-org.net"

# With no options, uses https://rekor.sigstore.dev and the Fulcio roots
- name: default
```

## Response

Here's an example of the response structure:

<details>
<summary>Click to expand</summary>

```
{
"apiVersion": "externaldata.gatekeeper.sh/v1alpha1",
"kind": "ProviderResponse",
"response": {
"items": [
{
"key": "my-registry/foobar:latest",
"value": {
"signatures": [
{
"id": {
"key": "LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0KTUZrd0V3WUhLb1pJemowQ0FRWUlLb1pJemowREFRY0RRZ0FFbGNvM3kvUjIzaXI3NnBDWnVWRTNPdjdUMC9kawo0Z0plNFd5Tk4xRzh5VmhpelAvaTc1MUdrZHZqTmZMQmZoVnFkc2xSVzhHWGRXakNqK2lXNTY1cHJnPT0KLS0tLS1FTkQgUFVCTElDIEtFWS0tLS0tCg=="
},
"payload": {
"critical": {
"identity": {
"docker-reference": "my-registry/foobar"
},
"image": {
"docker-manifest-digest": "sha256:3b2c249b772868bcfba7e4389dffe22fe5a7074c2d4b3cff777e860aacf76fbc"
},
"type": "cosign container image signature"
},
"optional": null
},
"verified": true
},
{
"id": {
"iss": "https://github.com/login/oauth",
"sub": "[email protected]"
},
"payload": {
"critical": {
"identity": {
"docker-reference": "my-registry/foobar"
},
"image": {
"docker-manifest-digest": "sha256:3b2c249b772868bcfba7e4389dffe22fe5a7074c2d4b3cff777e860aacf76fbc"
},
"type": "cosign container image signature"
},
"optional": null
},
"verified": true
},
{
"payload": {
"critical": {
"identity": {
"docker-reference": "my-registry/foobar"
},
"image": {
"docker-manifest-digest": "sha256:3b2c249b772868bcfba7e4389dffe22fe5a7074c2d4b3cff777e860aacf76fbc"
},
"type": "cosign container image signature"
},
"optional": null
},
"verified": false
}
]
}
}
]
}
}
```
</details>
121 changes: 121 additions & 0 deletions config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
// Copyright The Sigstore Authors.
//
// 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.

package main

import (
"os"

"github.com/pkg/errors"
"gopkg.in/yaml.v3"
)

var (
// DefaultOptions are the default verification options
DefaultOptions = &CheckOptions{
RekorURL: "https://rekor.sigstore.dev",
}

// DefaultVerifiers are the default verifiers for an image
DefaultVerifiers = []Verifier{
{
Options: DefaultOptions,
},
}

// DefaultConfig is the configuration used when none is provided
DefaultConfig = &Config{
Verifiers: DefaultVerifiers,
}
)

// LoadConfig loads configuration from a file. If a file isn't provided then it
// returns the default configuration.
func LoadConfig(confFile string) (*Config, error) {
if confFile == "" {
return DefaultConfig, nil
}

var c *Config

yamlReader, err := os.Open(confFile)
if err != nil {
return c, errors.Wrap(err, "reading config file")
}
defer yamlReader.Close()
decoder := yaml.NewDecoder(yamlReader)
decoder.KnownFields(true)

if err = decoder.Decode(&c); err != nil {
return c, errors.Wrap(err, "parsing config file")
}

return c, nil
}

// Config configures the provider
type Config struct {
// Verifiers is a list of verifiers used to verify image signatures
Verifiers []Verifier `yaml:"verifiers"`
}

// UnmarshalYAML configures the default verifiers if none are provided
func (c *Config) UnmarshalYAML(unmarshal func(interface{}) error) error {
type rawConfig Config
var raw rawConfig
if err := unmarshal(&raw); err != nil {
return err
}

if len(raw.Verifiers) == 0 {
raw.Verifiers = DefaultVerifiers
}

*c = Config(raw)

return nil
}

// Verifier verifies an image signature
type Verifier struct {
// Options defines verification options
Options *CheckOptions `yaml:"options,omitempty"`
}

// UnmarshalYAML sets default options for the verifier config when they aren't
// provided
func (v *Verifier) UnmarshalYAML(unmarshal func(interface{}) error) error {
type rawVerifier Verifier
var raw rawVerifier
if err := unmarshal(&raw); err != nil {
return err
}

if raw.Options == nil {
raw.Options = DefaultOptions
}

*v = Verifier(raw)

return nil
}

// CheckOptions are the options used to verify the signature of an image
type CheckOptions struct {
// Key is a path to a public key file, KMS URI or Kubernetes Secret
Key string `yaml:"key,omitempty"`

// RekorURL is the address of a rekor STL server
RekorURL string `yaml:"rekorURL,omitempty"`
}
Loading