Skip to content

Commit

Permalink
updates
Browse files Browse the repository at this point in the history
  • Loading branch information
pwittrock committed Nov 21, 2020
1 parent cb01d2c commit d38de1d
Show file tree
Hide file tree
Showing 7 changed files with 255 additions and 148 deletions.
159 changes: 159 additions & 0 deletions config-gen/apis/v1alpha1/certs.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
/*
Copyright 2020 The Kubernetes 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 (
"encoding/base64"
"fmt"

"github.com/cloudflare/cfssl/cli/genkey"
"github.com/cloudflare/cfssl/config"
"github.com/cloudflare/cfssl/csr"
"github.com/cloudflare/cfssl/helpers"
"github.com/cloudflare/cfssl/selfsign"
"sigs.k8s.io/kustomize/kyaml/fn/framework"
"sigs.k8s.io/kustomize/kyaml/kio"
"sigs.k8s.io/kustomize/kyaml/yaml"
)

var _ kio.Filter = &CertFilter{}

// CertFilter generates and injects certificates into webhook
type CertFilter struct {
*APIConfiguration
}

// Filter implements kio.Filter
func (c CertFilter) Filter(input []*yaml.RNode) ([]*yaml.RNode, error) {
if !c.Spec.Development.GenerateCert {
return input, nil
}
if err := c.generateCert(); err != nil {
return nil, err
}

s := &framework.Selector{
Kinds: []string{
"ValidatingWebhookConfiguration",
"MutatingWebhookConfiguration",
},
}
matches, err := s.GetMatches(&framework.ResourceList{Items: input})
if err != nil {
return nil, err
}
for i := range matches {
wh := matches[i].Field("webhooks")
if wh.IsNilOrEmpty() {
continue
}
err := wh.Value.VisitElements(func(node *yaml.RNode) error {
err := node.PipeE(yaml.LookupCreate(yaml.ScalarNode, "clientConfig", "caBundle"),
yaml.FieldSetter{StringValue: c.Status.CertCA})
if err != nil {
return err
}
err = node.PipeE(yaml.LookupCreate(yaml.ScalarNode, "clientConfig", "service", "namespace"),
yaml.FieldSetter{StringValue: c.Spec.Namespace})
if err != nil {
return err
}

return nil
})
if err != nil {
return nil, err
}
}

s = &framework.Selector{
Filter: func(n *yaml.RNode) bool {
// Allow-list conversion webhooks
m, _ := n.GetMeta()
if m.Kind != "CustomResourceDefinition" {
return true
}
return c.Spec.ConversionWebhooks[m.Name]
},
}
matches, err = s.GetMatches(&framework.ResourceList{Items: input})
if err != nil {
return nil, err
}
for i := range matches {
err := matches[i].PipeE(yaml.LookupCreate(yaml.ScalarNode, "spec", "conversion", "strategy"),
yaml.FieldSetter{StringValue: "Webhook"})
if err != nil {
return nil, err
}
err = matches[i].PipeE(yaml.LookupCreate(yaml.ScalarNode, "spec", "conversion", "webhookClientConfig", "caBundle"),
yaml.FieldSetter{StringValue: c.Status.CertCA})
if err != nil {
return nil, err
}
err = matches[i].PipeE(yaml.LookupCreate(yaml.ScalarNode, "spec", "conversion", "webhookClientConfig", "service", "name"),
yaml.FieldSetter{StringValue: "webhook-service"})
if err != nil {
return nil, err
}
err = matches[i].PipeE(yaml.LookupCreate(yaml.ScalarNode, "spec", "conversion", "webhookClientConfig", "service", "namespace"),
yaml.FieldSetter{StringValue: c.Spec.Namespace})
if err != nil {
return nil, err
}

err = matches[i].PipeE(yaml.LookupCreate(yaml.ScalarNode, "spec", "conversion", "webhookClientConfig", "service", "path"),
yaml.FieldSetter{StringValue: "/convert"})
if err != nil {
return nil, err
}
}

return input, nil
}

func (c CertFilter) generateCert() error {
var err error
var req = csr.New()
req.Hosts = []string{
fmt.Sprintf("webhook-service.%s.svc", c.Spec.Namespace),
fmt.Sprintf("webhook-service.%s.svc.cluster.local", c.Spec.Namespace),
}
req.CN = "kb-dev-controller-manager"

var key, csrPEM []byte
g := &csr.Generator{Validator: genkey.Validator}
csrPEM, key, err = g.ProcessRequest(req)
if err != nil {
return err
}
priv, err := helpers.ParsePrivateKeyPEM(key)
if err != nil {
return err
}

profile := config.DefaultConfig()
profile.Expiry = c.Spec.Development.CertDuration
cert, err := selfsign.Sign(priv, csrPEM, profile)
if err != nil {
return err
}

c.Status.CertCA = base64.StdEncoding.EncodeToString(cert)
c.Status.CertKey = base64.StdEncoding.EncodeToString(key)
return nil
}
4 changes: 2 additions & 2 deletions config-gen/apis/v1alpha1/controllergen.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,13 +47,13 @@ func (cgr ControllerGenFilter) Filter(input []*yaml.RNode) ([]*yaml.RNode, error
MaxDescLen: &desclen,
})
gens := genall.Generators{&crdGen}
if !cgr.Spec.DisableCreateRBAC {
if !cgr.Spec.Enabled("rbac") {
rbacGen := genall.Generator(rbac.Generator{
RoleName: cgr.Spec.Namespace + "-manager-role",
})
gens = append(gens, &rbacGen)
}
if cgr.Spec.EnableWebhooks {
if cgr.Spec.Enabled("webhooks") {
webhookGen := genall.Generator(webhook.Generator{})
gens = append(gens, &webhookGen)
}
Expand Down
10 changes: 5 additions & 5 deletions config-gen/apis/v1alpha1/patchetemplates.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ func getPatchTemplates(c *APIConfiguration) []framework.PatchTemplate {
"MutatingWebhookConfiguration",
},
},
Template: template.Must(template.New("conversion-webhook").Parse(`{{ if .Spec.EnableCertManager}}
Template: template.Must(template.New("conversion-webhook").Parse(`{{ if .Spec.Enabled "cert-manager" }}
metadata:
annotations:
cert-manager.io/inject-ca-from: {{ .Spec.Namespace }}/{{ .Spec.Name }}-serving-cert
Expand All @@ -61,15 +61,15 @@ metadata:
return c.Spec.ConversionWebhooks[m.Name]
},
},
Template: template.Must(template.New("conversion-webhook").Parse(`{{ if .Spec.EnableWebhooks}}
Template: template.Must(template.New("conversion-webhook").Parse(`{{ if .Spec.Enabled "webhooks" }}
spec:
conversion:
strategy: Webhook
webhookClientConfig:
# this is "\n" used as a placeholder, otherwise it will be rejected by the apiserver for being blank,
# but we're going to set it later using the cert-manager (or potentially a patch if not using cert-manager)
{{- if .Spec.Development.GenerateCert }}
caBundle: {{ .Spec.Development.CA }}
caBundle: {{ .Status.CertCA }}
{{- end }}
service:
namespace: {{ .Spec.Namespace }}
Expand All @@ -81,7 +81,7 @@ spec:
// Auth proxy patch for the controller-manager
{
Selector: controllerManagerSelector,
Template: template.Must(template.New("controller-manager-auth-proxy-patch").Parse(`{{ if not .Spec.DisableAuthProxy}}
Template: template.Must(template.New("controller-manager-auth-proxy-patch").Parse(`{{ if not .Spec.DisableAuthProxy }}
spec:
template:
spec:
Expand All @@ -106,7 +106,7 @@ spec:
// Webhooks patch for the controller-manager
{
Selector: controllerManagerSelector,
Template: template.Must(template.New("controller-manager-webhooks").Parse(`{{ if .Spec.EnableWebhooks }}
Template: template.Must(template.New("controller-manager-webhooks").Parse(`{{ if .Spec.Enabled "webhooks" }}
spec:
template:
spec:
Expand Down
102 changes: 7 additions & 95 deletions config-gen/apis/v1alpha1/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,27 +17,17 @@ limitations under the License.
package v1alpha1

import (
"encoding/base64"
"fmt"
"time"

"github.com/cloudflare/cfssl/cli/genkey"
"github.com/cloudflare/cfssl/config"
"github.com/cloudflare/cfssl/csr"
"github.com/cloudflare/cfssl/helpers"
"github.com/cloudflare/cfssl/selfsign"
"github.com/spf13/cobra"
"sigs.k8s.io/kustomize/kyaml/errors"
"sigs.k8s.io/kustomize/kyaml/fn/framework"
"sigs.k8s.io/kustomize/kyaml/yaml"
)

// NewCommand returns a new cobra command
func NewCommand() cobra.Command {
fc := &APIConfiguration{}

// read Project.yaml into struct

return framework.TemplateCommand{
MergeResources: true,
API: fc,
Expand All @@ -51,7 +41,7 @@ func NewCommand() cobra.Command {
// Validate the input
if fc.Spec.Name == "" {
if fc.Name == "" {
return errors.Errorf("must specify name")
return errors.Errorf("must specify PROJECT projectName field")
}
fc.Spec.Name = fc.Name
}
Expand All @@ -62,7 +52,7 @@ func NewCommand() cobra.Command {
fc.Spec.Namespace = fc.Spec.Name + "-system"
}
if fc.Spec.Image == "" {
return errors.Errorf("must specify image")
return errors.Errorf("must specify PROJECT image field")
}
if fc.Spec.Development.CertDuration == 0 {
d := time.Hour * 1
Expand All @@ -75,97 +65,19 @@ func NewCommand() cobra.Command {
if err != nil {
return err
}
return doCerts(fc, rl)
return nil
},
Templates: configTemplates,
PatchTemplates: getPatchTemplates(fc),
PostProcess: func(rl *framework.ResourceList) error {
// Sort the resources
var err error
rl.Items, err = SortFilter{APIConfiguration: fc}.Filter(rl.Items)
return err
},
}.GetCommand()
}

func doCerts(fc *APIConfiguration, rl *framework.ResourceList) error {
if !fc.Spec.Development.GenerateCert {
return nil
}
if err := generateCert(fc); err != nil {
return err
}

s := &framework.Selector{
Kinds: []string{
"CustomResourceDefinition",
"ValidatingWebhookConfiguration",
"MutatingWebhookConfiguration",
},
}
matches, err := s.GetMatches(rl)
if err != nil {
return err
}
for i := range matches {
wh := matches[i].Field("webhooks")
if wh.IsNilOrEmpty() {
continue
}
err := wh.Value.VisitElements(func(node *yaml.RNode) error {
err := node.PipeE(yaml.LookupCreate(yaml.ScalarNode, "clientConfig", "caBundle"),
yaml.FieldSetter{StringValue: fc.Spec.Development.CA})
if err != nil {
return err
}
err = node.PipeE(yaml.LookupCreate(yaml.ScalarNode, "clientConfig", "service", "namespace"),
yaml.FieldSetter{StringValue: fc.Spec.Namespace})
rl.Items, err = CertFilter{APIConfiguration: fc}.Filter(rl.Items)
if err != nil {
return err
}

return nil
})
if err != nil {
rl.Items, err = SortFilter{APIConfiguration: fc}.Filter(rl.Items)
return err
}
}

return nil
}

func generateCert(api *APIConfiguration) error {
var err error
var req = csr.New()
req.Hosts = []string{
fmt.Sprintf("webhook-service.%s.svc", api.Spec.Namespace),
fmt.Sprintf("webhook-service.%s.svc.cluster.local", api.Spec.Namespace),
}
req.CN = "kb-dev-controller-manager"
// req.KeyRequest.A = "rsa"
// req.KeyRequest.S = 2048

var key, csrPEM []byte
g := &csr.Generator{Validator: genkey.Validator}
csrPEM, key, err = g.ProcessRequest(req)
if err != nil {
return err
}
priv, err := helpers.ParsePrivateKeyPEM(key)
if err != nil {
return err
}

profile := config.DefaultConfig()
profile.Expiry = api.Spec.Development.CertDuration

cert, err := selfsign.Sign(priv, csrPEM, profile)
if err != nil {
return err
}

api.Spec.Development.CA = base64.StdEncoding.EncodeToString(cert)
api.Spec.Development.Key = base64.StdEncoding.EncodeToString(key)

return nil
},
}.GetCommand()
}
Loading

0 comments on commit d38de1d

Please sign in to comment.