Skip to content

Commit

Permalink
Add ImagePolicy to support signature verification
Browse files Browse the repository at this point in the history
This enhancement propose an ImagePolicy CRD to provide a way to set image signature verification configuration on Openshift.

Signed-off-by: Qi Wang <[email protected]>
  • Loading branch information
QiWang19 committed May 17, 2023
1 parent 344d4bb commit 4e757d5
Showing 1 changed file with 336 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,336 @@
---
title: add-ImagePolicy-to-config.openshift.io-v1alpha1
authors:
- "@QiWang19"
reviewers: # Include a comment about what domain expertise a reviewer is expected to bring and what area of the enhancement you expect them to focus on. For example: - "@networkguru, for networking aspects, please look at IP bootstrapping aspect"
- "@saschagrunert, for API design, implementation details and graduation criteria"
approvers: # A single approver is preferred, the role of the approver is to raise important questions, help ensure the enhancement receives reviews from all applicable areas/SMEs, and determine when consensus is achieved such that the EP can move forward to implementation. Having multiple approvers makes it difficult to determine who is responsible for the actual approval.
- "@mrunalp"
api-approvers: # In case of new or modified APIs or API extensions (CRDs, aggregated apiservers, webhooks, finalizers). If there is no API change, use "None"
- "@mrunalp"
creation-date: yyyy-mm-dd
last-updated: yyyy-mm-dd
tracking-link: # link to the tracking ticket (for example: Jira Feature or Epic ticket) that corresponds to this enhancement
- https://issues.redhat.com/browse/OCPNODE-1628
see-also:
- "/enhancements/this-other-neat-thing.md"
replaces:
- "/enhancements/that-less-than-great-idea.md"
superseded-by:
- "/enhancements/our-past-effort.md"
---

# Add CRD ImagePolicy to config.openshift.io/v1alpha1

## Summary

This enhancement propose an ImagePolicy CRD to provide a way to set image signature verification configuration on Openshift.

## Motivation

### User Stories

As an OpenShift user, I want to verify the container images signed using sigstore
tools, so that I can utilize the increased security of my software supply chain.

The user can create an ImagePolicy instance specifying the images/repositories to be verified and their policy. The MCO will write the configuration for signature verification. Once this is done, CRI-O can verify the images/repositories.

### Goals

- MCO container runtime config controller watches ImagePolicy instance in different namespaces and merges the instances for each namespace into a single containers-policy.json in a predefined /path/to/policies/\<NAMESPACE\>.json.

- CRI-O can verify Cosign signature signed images using configuration from ImagePolicy

### Non-Goals

ImagePolicy CRD does not implements cosign with custom Fulcio and Rekor instance.

## Proposal

### Workflow Description

**cluster administrator** is a human user responsible for adding signature verification configurations in
cluster scope.
1. The cluster administrator creates ImagePolicy yaml file with `namespace: opesnhift-config`.
2. The cluster administrator creates ImagePolicy instance using `oc create -f imagepolicy.yaml`.
3. The cluster administrator can get the merged cluster scope policies from `status` of ImagePolicy instances.
4. The cluster administrator can delete the signature verification configuration by deleting its ImagePolicy instances.

**application administrator** is a human user responsible for
adding signature verification configurations for specific namespace.

1. The application administrator creates ImagePolicy yaml file for namespace that is not `namespace: opesnhift-config`
2. The application administrator creates ImagePolicy instance using `oc create -f imagepolicy.yaml`.
3. The application administrator can get the merged cluster policy and policy for certain namespace from `status` of ImagePolicy instances.
4. The application administrator can delete the signature verification configuration by deleting its ImagePolicy instances.

### API Extensions

#### Type definitions

```go
type ImagePolicySpec struct {
// images holds images/repositories to be verified
Images []Image `json:"images"`
// policy defines the verification policy
Policy Policy `json:"policy"`
}

// Image defines the list of images assigned to a policy.
// For more information about the format, see the document
// about the location field:
// https://github.com/containers/image/blob/main/
// docs/containers-policy.json.5.md#docker
type Image struct {
Hostname string `json:"hostname,omitempty"`
}

type Policy struct {
// OIDCIssuer contains the expected OIDC issuer.
// Requires SubjectEmail to be set and KeyData to be empty.
// Example: "https://expected.OIDC.issuer/"
OIDCIssuer string `json:"oidcIssuer,omitempty"`

// SubjectEmail holds the email address of the subject.
// Example: "[email protected]"
// Requires OIDCIssuer to be set and KeyData to be empty.
SubjectEmail string `json:"subjectEmail,omitempty"`

// KeyData contains inline base64 data of the public key.
// Can be empty if the image got signed keyless.
// Requires OIDCIssuer and SubjectEmail to be empty.
KeyData string `json:"keyData,omitempty"`

// SignedIdentity specifies what image identity the signature
// claims about the image.
SignedIdentity Identity `json:"signedIdentity,omitempty"`

// FulcioCAData contains inline base64 data for the fulcio
// CA certificate.
// Defaults to the base64 encoded contents of:
// https://raw.githubusercontent.com/sigstore/root-signing/main/
// targets/fulcio_v1.crt.pem
// QUESTION: Can we omit it in favor of the upstream default?
FulcioCAData string `json:"fulcioCAData,omitempty"`

// RekorKeyData contains inline base64 data of the rekor public key.
// Defaults to the base64 encoded contents of:
// https://raw.githubusercontent.com/sigstore/root-signing/main/
// targets/rekor.pub
// QUESTION: Can we omit it in favor of the upstream default?
RekorKeyData string `json:"rekorKeyData,omitempty"`
}

type Identity struct {
// Defaults to "matchRepository"
IdentityMatchPolicy IdentityMatchPolicy `json:"identityMatchPolicy,…"`
Prefix string `json:"prefix,omitempty"`
SignedPrefix string `json:"signedPrefix,omitempty"`
DockerReference string `json:"dockerReference,omitempty"`
DockerRepository string `json:"dockerRepository,omitempty"`
}

type IdentityMatchPolicy string

const (
IdentityMatchPolicyMatchRepository = "matchRepository"
IdentityMatchPolicyMatchExact = "matchExact"
IdentityMatchPolicyRemapIdentity = "remapIdentity"
IdentityMatchPolicyMatchRepoDigestOrExact = "matchRepoDigestOrExact"
IdentityMatchPolicyExactRepository = "exactRepository"
IdentityMatchPolicyExactReference = "exactReference"
)

type ImagePolicyStatus struct {
// PolicyJSON contains the whole policy applied to the namespace
// which got written to disk. This includes cluster-wide policies
// from the `openshift-config` namespace as well.
PolicyJSON string `json:"policyJSON,omitempty"`

// QUESTION: DO we need conditions?
Conditions []metav1.Condition `json:"conditions,omitempty"`
}
```

### Implementation Details/Notes/Constraints [optional]

#### Update container runtime config controller to watch ImagePolicy

MCO container runtime config controller ImagePolicy syncHandler updates the signature verification configurations:
- retrieves all the ImagePolicy instances on the cluster.
- validates conflicting data from ImagePolicy instances.
- adds following configurations to a single machine config
- merges the instances for each namespace into a single [containers-policy.json](https://github.com/containers/image/blob/main/docs/containers-policy.json.5.md) in a predefined /path/to/policies/\<NAMESPACE\>.json.
If no policy exists in a namespace, use the current default of:

```yaml
{ "default": [{ "type": "insecureAcceptAnything" }] }
```

If a single policy exists, use the default:

```yaml
{ "default": [{"type": "reject"}] }
```

- adds [/etc/containers/registries.d/*.yaml](https://github.com/containers/image/blob/main/docs/containers-registries.d.5.md) to allow matching sigstore signatures, for example:

```yaml
docker:
my-registry/image:
use-sigstore-attachments: true
```

Alternatively, we can enable it node wide:

```yaml
default-docker:
use-sigstore-attachments: true
```
- merges cluster scoped with namespaced ImagePolicy as a json string and update `status` of each ImagePolicy.
Once an ImagePolicy object gets created/updated, container runtime config controller will call the syncHandler.
Once an ImagePolicy object gets deleted, container runtime config controller will delete the machine config and run the syncHandler

#### Notes

ImagePolicy is defined as namespaced CRD. `namespace: openshift-config` is used for cluster policy.

### Risks and Mitigations

Risk: The cluster scoped and namespace policies overwrite

Mitigation: MCO container runtime config controller makes sure namespaced policies for an image cannot override global definitions when merging cluster openshift-config policies and namespaced policies into status field of ImagePolicy instances.

### Drawbacks

## Design Details

### Open Questions [optional]

### Test Plan

**Note:** *Section not required until targeted at a release.*

MCO container runtime config controller can add unit tests and e2e tests.
- unit test: verify the policies from ImagePolicy instances merged correctly and the controller writes correct format policy.json
- e2e test: verify the MCO writes configuration to the correct location


### Graduation Criteria

**Note:** *Section not required until targeted at a release.*

Define graduation milestones.

These may be defined in terms of API maturity, or as something else. Initial proposal
should keep this high-level with a focus on what signals will be looked at to
determine graduation.

Consider the following in developing the graduation criteria for this
enhancement:

- Maturity levels
- [`alpha`, `beta`, `stable` in upstream Kubernetes][maturity-levels]
- `Dev Preview`, `Tech Preview`, `GA` in OpenShift
- [Deprecation policy][deprecation-policy]

Clearly define what graduation means by either linking to the [API doc definition](https://kubernetes.io/docs/concepts/overview/kubernetes-api/#api-versioning),
or by redefining what graduation means.

In general, we try to use the same stages (alpha, beta, GA), regardless how the functionality is accessed.

[maturity-levels]: https://git.k8s.io/community/contributors/devel/sig-architecture/api_changes.md#alpha-beta-and-stable-versions
[deprecation-policy]: https://kubernetes.io/docs/reference/using-api/deprecation-policy/

**If this is a user facing change requiring new or updated documentation in [openshift-docs](https://github.com/openshift/openshift-docs/),
please be sure to include in the graduation criteria.**

**Examples**: These are generalized examples to consider, in addition
to the aforementioned [maturity levels][maturity-levels].

#### Dev Preview -> Tech Preview

- Ability to utilize the enhancement end to end
- End user documentation, relative API stability
- Sufficient test coverage
- Gather feedback from users rather than just developers
- Enumerate service level indicators (SLIs), expose SLIs as metrics
- Write symptoms-based alerts for the component(s)

#### Tech Preview -> GA

- More testing (upgrade, downgrade, scale)
- Sufficient time for feedback
- Available by default
- Backhaul SLI telemetry
- Document SLOs for the component
- Conduct load testing
- User facing documentation created in [openshift-docs](https://github.com/openshift/openshift-docs/)

**For non-optional features moving to GA, the graduation criteria must include
end to end tests.**

#### Removing a deprecated feature

Not applicable.

### Upgrade / Downgrade Strategy

Upgrade expectations:
In order to use ImagePolicy, an existing cluster will have to make on upgrade.

Downgrade expectations:
- Not applicable.
If `N` does not support ImagePolicy CRD, `N+1`supports IamgePolicy. It is not expected that the ImagePolicy related to the failure `N->N+1`. New resources should not be created during `N->N+1`.


### Version Skew Strategy

The MCO does not require skew check.

### Operational Aspects of API Extensions

- Use-cases that requires over 1000 instances of the CRD is rare, not impacting
general API throughput.

#### Failure Modes

- CR field syntax error failure reported from CLI
- CR conflicting value failure reported by machine config controller logs
- MCO rolling out configuration file failure reported by MCO
- If the signature validation fails, then CRI-O will report that in the same way as for any other pull failure. Further enhancements to the kubelet, CRI and CRI-O error handling can be achieved in future Kubernetes releases.

The above errors should not impact the overall cluster health
OCP Node team is likely to be called upon in case of escalation with one of the failure modes.

#### Support Procedures

- detect the failure modes in a support situation, describe possible symptoms (events, metrics,
alerts, which log output in which component)
- If the ImagePolicy CR does not follow the syntax requirements, api-server will fail when creating the objects.
- If the ImagePolicy CR is not rolled out by MCO, machine-config-controller logs will shows error with the reason.

- disable the API extension (e.g. remove MutatingWebhookConfiguration `xyz`, remove APIService `foo`)
- Disabling/removing the CRD is not possible without removing the CR instances. Customer will lose data.

- What consequences does it have on existing, running workloads?
- No impact. CRI-O does not verify signature verification for running containers.

- What consequences does it have for newly created workloads?
- In order to verify signature for new pods, ImagePolicy instances should be successfully rolled out before creating new workloads.

- Does functionality fail gracefully and will work resume when re-enabled without risking
- User can create another objects if previous objects failed to roll out.

## Implementation History

[OCPNODE-1628: Sigstore Support - OpenShift Container Image Validation (Dev Preview)](https://issues.redhat.com/browse/OCPNODE-1628) epic will keep track of the implementation.

## Alternatives

Not applicable.

## Infrastructure Needed [optional]

- Registry proxies like registry.k8s.io are not natively usable: https://github.com/containers/image/issues/1952
Workaround: using remapIdentity

0 comments on commit 4e757d5

Please sign in to comment.