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

v1beta1 API for cosigned #1890

Merged
merged 7 commits into from May 18, 2022
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
49 changes: 43 additions & 6 deletions cmd/cosign/policy_webhook/main.go
Expand Up @@ -28,11 +28,14 @@ import (
"knative.dev/pkg/webhook"
"knative.dev/pkg/webhook/certificates"
"knative.dev/pkg/webhook/resourcesemantics"
"knative.dev/pkg/webhook/resourcesemantics/conversion"
"knative.dev/pkg/webhook/resourcesemantics/defaulting"
"knative.dev/pkg/webhook/resourcesemantics/validation"
"sigs.k8s.io/release-utils/version"

"github.com/sigstore/cosign/pkg/apis/cosigned"
"github.com/sigstore/cosign/pkg/apis/cosigned/v1alpha1"
"github.com/sigstore/cosign/pkg/apis/cosigned/v1beta1"
"github.com/sigstore/cosign/pkg/reconciler/clusterimagepolicy"

// Register the provider-specific plugins
Expand Down Expand Up @@ -61,6 +64,13 @@ var (
validatingWebhookName = flag.String("validating-webhook-name", "validating.clusterimagepolicy.sigstore.dev", "The name of the validating webhook configuration as well as the webhook name that is automatically configured, if exists, with different rules and client settings setting how the admission requests to be dispatched to policy-webhook.")
)

var types = map[schema.GroupVersionKind]resourcesemantics.GenericCRD{
// v1alpha1
v1alpha1.SchemeGroupVersion.WithKind("ClusterImagePolicy"): &v1alpha1.ClusterImagePolicy{},
// v1beta1
v1beta1.SchemeGroupVersion.WithKind("ClusterImagePolicy"): &v1beta1.ClusterImagePolicy{},
}

func main() {
opts := webhook.Options{
ServiceName: "policy-webhook",
Expand All @@ -81,6 +91,7 @@ func main() {
clusterimagepolicy.NewController,
NewPolicyValidatingAdmissionController,
NewPolicyMutatingAdmissionController,
newConversionController,
)
}

Expand All @@ -89,9 +100,7 @@ func NewPolicyValidatingAdmissionController(ctx context.Context, cmw configmap.W
ctx,
*validatingWebhookName,
"/validating",
map[schema.GroupVersionKind]resourcesemantics.GenericCRD{
v1alpha1.SchemeGroupVersion.WithKind("ClusterImagePolicy"): &v1alpha1.ClusterImagePolicy{},
},
types,
func(ctx context.Context) context.Context {
return ctx
},
Expand All @@ -104,12 +113,40 @@ func NewPolicyMutatingAdmissionController(ctx context.Context, cmw configmap.Wat
ctx,
*mutatingWebhookName,
"/defaulting",
map[schema.GroupVersionKind]resourcesemantics.GenericCRD{
v1alpha1.SchemeGroupVersion.WithKind("ClusterImagePolicy"): &v1alpha1.ClusterImagePolicy{},
},
types,
func(ctx context.Context) context.Context {
return ctx
},
true,
)
}

func newConversionController(ctx context.Context, cmw configmap.Watcher) *controller.Impl {
// nolint: revive
var (
v1alpha1GroupVersion = v1alpha1.SchemeGroupVersion.Version
v1beta1GroupVersion = v1beta1.SchemeGroupVersion.Version
)

return conversion.NewConversionController(ctx,
// The path on which to serve the webhook
"/resource-conversion",

// Specify the types of custom resource definitions that should be converted
map[schema.GroupKind]conversion.GroupKindConversion{
v1beta1.Kind("ClusterImagePolicy"): {
DefinitionName: cosigned.ClusterImagePolicyResource.String(),
HubVersion: v1alpha1GroupVersion,
Zygotes: map[string]conversion.ConvertibleObject{
v1alpha1GroupVersion: &v1alpha1.ClusterImagePolicy{},
v1beta1GroupVersion: &v1beta1.ClusterImagePolicy{},
},
},
},

// A function that infuses the context passed to ConvertTo/ConvertFrom/SetDefaults with custom metadata
func(ctx context.Context) context.Context {
return ctx
},
)
}
4 changes: 2 additions & 2 deletions hack/update-codegen.sh
Expand Up @@ -45,15 +45,15 @@ group "Kubernetes Codegen"
# instead of the $GOPATH directly. For normal projects this can be dropped.
${CODEGEN_PKG}/generate-groups.sh "deepcopy,client,informer,lister" \
github.com/sigstore/cosign/pkg/client github.com/sigstore/cosign/pkg/apis \
"cosigned:v1alpha1" \
"cosigned:v1alpha1 cosigned:v1beta1" \
--go-header-file ${REPO_ROOT_DIR}/hack/boilerplate/boilerplate.go.txt

group "Knative Codegen"

# Knative Injection
${KNATIVE_CODEGEN_PKG}/hack/generate-knative.sh "injection" \
github.com/sigstore/cosign/pkg/client github.com/sigstore/cosign/pkg/apis \
"cosigned:v1alpha1" \
"cosigned:v1alpha1 cosigned:v1beta1" \
--go-header-file ${REPO_ROOT_DIR}/hack/boilerplate/boilerplate.go.txt

group "Update CRD Schema"
Expand Down
10 changes: 10 additions & 0 deletions pkg/apis/cosigned/register.go
Expand Up @@ -14,7 +14,17 @@

package cosigned

import "k8s.io/apimachinery/pkg/runtime/schema"

const (
// GroupName is the name of the API group.
GroupName = "cosigned.sigstore.dev"
)

var (
// ClusterImagePolicyResource represents a ClusterImagePolicy
ClusterImagePolicyResource = schema.GroupResource{
Group: GroupName,
Resource: "clusterimagepolicies",
}
)
192 changes: 192 additions & 0 deletions pkg/apis/cosigned/v1alpha1/clusterimagepolicy_conversion.go
@@ -0,0 +1,192 @@
// Copyright 2022 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 v1alpha1

import (
"context"
"fmt"

"github.com/sigstore/cosign/pkg/apis/cosigned/v1beta1"
v1 "k8s.io/api/core/v1"
"knative.dev/pkg/apis"
)

var _ apis.Convertible = (*ClusterImagePolicy)(nil)

// ConvertTo implements api.Convertible
func (c *ClusterImagePolicy) ConvertTo(ctx context.Context, obj apis.Convertible) error {
switch sink := obj.(type) {
case *v1beta1.ClusterImagePolicy:
sink.ObjectMeta = c.ObjectMeta
return c.Spec.ConvertTo(ctx, &sink.Spec)
default:
return fmt.Errorf("unknown version, got: %T", sink)
}
}

// ConvertFrom implements api.Convertible
func (c *ClusterImagePolicy) ConvertFrom(ctx context.Context, obj apis.Convertible) error {
switch source := obj.(type) {
case *v1beta1.ClusterImagePolicy:
c.ObjectMeta = source.ObjectMeta
return c.Spec.ConvertFrom(ctx, &source.Spec)
default:
return fmt.Errorf("unknown version, got: %T", c)
}
}

func (spec *ClusterImagePolicySpec) ConvertTo(ctx context.Context, sink *v1beta1.ClusterImagePolicySpec) error {
for _, image := range spec.Images {
sink.Images = append(sink.Images, v1beta1.ImagePattern{Glob: image.Glob})
}
for _, authority := range spec.Authorities {
v1beta1Authority := v1beta1.Authority{}
err := authority.ConvertTo(ctx, &v1beta1Authority)
if err != nil {
return err
}
sink.Authorities = append(sink.Authorities, v1beta1Authority)
}
return nil
}

func (authority *Authority) ConvertTo(ctx context.Context, sink *v1beta1.Authority) error {
sink.Name = authority.Name
if authority.CTLog != nil && authority.CTLog.URL != nil {
sink.CTLog = &v1beta1.TLog{URL: authority.CTLog.URL.DeepCopy()}
}
for _, source := range authority.Sources {
v1beta1Source := v1beta1.Source{}
v1beta1Source.OCI = source.OCI
for _, sps := range source.SignaturePullSecrets {
v1beta1Source.SignaturePullSecrets = append(v1beta1Source.SignaturePullSecrets, v1.LocalObjectReference{Name: sps.Name})
}
sink.Sources = append(sink.Sources, v1beta1Source)
}
for _, att := range authority.Attestations {
v1beta1Att := v1beta1.Attestation{}
v1beta1Att.Name = att.Name
v1beta1Att.PredicateType = att.PredicateType
if att.Policy != nil {
v1beta1Att.Policy = &v1beta1.Policy{
Type: att.Policy.Type,
Data: att.Policy.Data,
}
v1beta1Att.Policy.URL = att.Policy.URL.DeepCopy()
if att.Policy.ConfigMapRef != nil {
v1beta1Att.Policy.ConfigMapRef = &v1beta1.ConfigMapReference{
Name: att.Policy.ConfigMapRef.Name,
Namespace: att.Policy.ConfigMapRef.Namespace,
}
}
}
sink.Attestations = append(sink.Attestations, v1beta1Att)
}
if authority.Key != nil {
sink.Key = &v1beta1.KeyRef{}
authority.Key.ConvertTo(ctx, sink.Key)
}
if authority.Keyless != nil {
sink.Keyless = &v1beta1.KeylessRef{
URL: authority.Keyless.URL.DeepCopy(),
}
for _, id := range authority.Keyless.Identities {
sink.Keyless.Identities = append(sink.Keyless.Identities, v1beta1.Identity{Issuer: id.Issuer, Subject: id.Subject})
}
if authority.Keyless.CACert != nil {
sink.Keyless.CACert = &v1beta1.KeyRef{}
authority.Keyless.CACert.ConvertTo(ctx, sink.Keyless.CACert)
}
}
return nil
}

func (key *KeyRef) ConvertTo(ctx context.Context, sink *v1beta1.KeyRef) {
sink.SecretRef = key.SecretRef.DeepCopy()
sink.Data = key.Data
sink.KMS = key.KMS
}

func (spec *ClusterImagePolicySpec) ConvertFrom(ctx context.Context, source *v1beta1.ClusterImagePolicySpec) error {
for _, image := range source.Images {
spec.Images = append(spec.Images, ImagePattern{Glob: image.Glob})
}
for i := range source.Authorities {
authority := Authority{}
err := authority.ConvertFrom(ctx, &source.Authorities[i])
if err != nil {
return err
}
spec.Authorities = append(spec.Authorities, authority)
}
return nil
}

func (authority *Authority) ConvertFrom(ctx context.Context, source *v1beta1.Authority) error {
authority.Name = source.Name
if source.CTLog != nil && source.CTLog.URL != nil {
authority.CTLog = &TLog{URL: source.CTLog.URL.DeepCopy()}
}
for _, s := range source.Sources {
src := Source{}
src.OCI = s.OCI
for _, sps := range s.SignaturePullSecrets {
src.SignaturePullSecrets = append(src.SignaturePullSecrets, v1.LocalObjectReference{Name: sps.Name})
}
authority.Sources = append(authority.Sources, src)
}
for _, att := range source.Attestations {
attestation := Attestation{}
attestation.Name = att.Name
attestation.PredicateType = att.PredicateType
if att.Policy != nil {
attestation.Policy = &Policy{
Type: att.Policy.Type,
Data: att.Policy.Data,
}
attestation.Policy.URL = att.Policy.URL.DeepCopy()
if att.Policy.ConfigMapRef != nil {
attestation.Policy.ConfigMapRef = &ConfigMapReference{
Name: att.Policy.ConfigMapRef.Name,
Namespace: att.Policy.ConfigMapRef.Namespace,
}
}
}
authority.Attestations = append(authority.Attestations, attestation)
}
if source.Key != nil {
authority.Key = &KeyRef{}
authority.Key.ConvertFrom(ctx, source.Key)
}
if source.Keyless != nil {
authority.Keyless = &KeylessRef{
URL: source.Keyless.URL.DeepCopy(),
}
for _, id := range source.Keyless.Identities {
authority.Keyless.Identities = append(authority.Keyless.Identities, Identity{Issuer: id.Issuer, Subject: id.Subject})
}
if source.Keyless.CACert != nil {
authority.Keyless.CACert = &KeyRef{}
authority.Keyless.CACert.ConvertFrom(ctx, source.Keyless.CACert)
}
}
return nil
}

func (key *KeyRef) ConvertFrom(ctx context.Context, source *v1beta1.KeyRef) {
key.SecretRef = source.SecretRef.DeepCopy()
key.Data = source.Data
key.KMS = source.KMS
}