From bb17d4f2cb08de6f3d82c13bd56c699f389b3c8f Mon Sep 17 00:00:00 2001
From: Mariano Cano <mariano@smallstep.com>
Date: Mon, 12 Aug 2019 16:10:32 -0700
Subject: [PATCH] Add StepIssuer spec and generated files.

---
 api/v1beta1/groupversion_info.go              |  35 ++++
 api/v1beta1/stepissuer_types.go               | 152 +++++++++++++++
 api/v1beta1/zz_generated.deepcopy.go          | 178 ++++++++++++++++++
 .../certmanager.step.sm_stepissuers.yaml      | 126 +++++++++++++
 config/crd/kustomization.yaml                 |  21 +++
 config/crd/kustomizeconfig.yaml               |  17 ++
 .../patches/cainjection_in_stepissuers.yaml   |   8 +
 .../crd/patches/webhook_in_stepissuers.yaml   |  17 ++
 config/rbac/role.yaml                         |  45 +++++
 config/webhook/manifests.yaml                 |   0
 10 files changed, 599 insertions(+)
 create mode 100644 api/v1beta1/groupversion_info.go
 create mode 100644 api/v1beta1/stepissuer_types.go
 create mode 100644 api/v1beta1/zz_generated.deepcopy.go
 create mode 100644 config/crd/bases/certmanager.step.sm_stepissuers.yaml
 create mode 100644 config/crd/kustomization.yaml
 create mode 100644 config/crd/kustomizeconfig.yaml
 create mode 100644 config/crd/patches/cainjection_in_stepissuers.yaml
 create mode 100644 config/crd/patches/webhook_in_stepissuers.yaml
 create mode 100644 config/rbac/role.yaml
 create mode 100644 config/webhook/manifests.yaml

diff --git a/api/v1beta1/groupversion_info.go b/api/v1beta1/groupversion_info.go
new file mode 100644
index 0000000..5ac5135
--- /dev/null
+++ b/api/v1beta1/groupversion_info.go
@@ -0,0 +1,35 @@
+/*
+
+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 v1beta1 contains API Schema definitions for the certmanager v1beta1 API group
+// +kubebuilder:object:generate=true
+// +groupName=certmanager.step.sm
+package v1beta1
+
+import (
+	"k8s.io/apimachinery/pkg/runtime/schema"
+	"sigs.k8s.io/controller-runtime/pkg/scheme"
+)
+
+var (
+	// GroupVersion is group version used to register these objects
+	GroupVersion = schema.GroupVersion{Group: "certmanager.step.sm", Version: "v1beta1"}
+
+	// SchemeBuilder is used to add go types to the GroupVersionKind scheme
+	SchemeBuilder = &scheme.Builder{GroupVersion: GroupVersion}
+
+	// AddToScheme adds the types in this group-version to the given scheme.
+	AddToScheme = SchemeBuilder.AddToScheme
+)
diff --git a/api/v1beta1/stepissuer_types.go b/api/v1beta1/stepissuer_types.go
new file mode 100644
index 0000000..e85c36c
--- /dev/null
+++ b/api/v1beta1/stepissuer_types.go
@@ -0,0 +1,152 @@
+/*
+
+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 v1beta1
+
+import (
+	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+)
+
+// EDIT THIS FILE!  THIS IS SCAFFOLDING FOR YOU TO OWN!
+// NOTE: json tags are required.  Any new fields you add must have json tags for the fields to be serialized.
+
+func init() {
+	SchemeBuilder.Register(&StepIssuer{}, &StepIssuerList{})
+}
+
+// StepIssuerSpec defines the desired state of StepIssuer
+type StepIssuerSpec struct {
+	// INSERT ADDITIONAL SPEC FIELDS - desired state of cluster
+	// Important: Run "make" to regenerate code after modifying this file
+
+	// URL is the base URL for the step certificates instance.
+	URL string `json:"url"`
+
+	// Provisioner contains the step certificates provisioner configuration.
+	Provisioner StepProvisioner `json:"provisioner"`
+
+	// CABundle is a base64 encoded TLS certificate used to verify connections
+	// to the step certificates server. If not set the system root certificates
+	// are used to validate the TLS connection.
+	// +optional
+	CABundle []byte `json:"caBundle,omitempty"`
+}
+
+// StepIssuerStatus defines the observed state of StepIssuer
+type StepIssuerStatus struct {
+	// INSERT ADDITIONAL STATUS FIELD - define observed state of cluster
+	// Important: Run "make" to regenerate code after modifying this file
+
+	// +optional
+	Conditions []StepIssuerCondition `json:"conditions,omitempty"`
+}
+
+// +kubebuilder:object:root=true
+
+// StepIssuer is the Schema for the stepissuers API
+type StepIssuer struct {
+	metav1.TypeMeta   `json:",inline"`
+	metav1.ObjectMeta `json:"metadata,omitempty"`
+
+	Spec   StepIssuerSpec   `json:"spec,omitempty"`
+	Status StepIssuerStatus `json:"status,omitempty"`
+}
+
+// +kubebuilder:object:root=true
+
+// StepIssuerList contains a list of StepIssuer
+type StepIssuerList struct {
+	metav1.TypeMeta `json:",inline"`
+	metav1.ListMeta `json:"metadata,omitempty"`
+	Items           []StepIssuer `json:"items"`
+}
+
+// SecretKeySelector contains the reference to a secret.
+type SecretKeySelector struct {
+	// The name of the secret in the pod's namespace to select from.
+	Name string `json:"name"`
+
+	// The key of the secret to select from. Must be a valid secret key.
+	// +optional
+	Key string `json:"key,omitempty"`
+}
+
+// StepProvisioner contains the configuration used to create step certificate
+// tokens used to grant certificates.
+type StepProvisioner struct {
+	// Names is the name of the JWK provisioner.
+	Name string `json:"name"`
+
+	// KeyID is the kid property of the JWK provisioner.
+	KeyID string `json:"kid"`
+
+	// PasswordRef is a reference to a Secret containing the provisioner
+	// password used to decrypt the provisioner private key.
+	PasswordRef SecretKeySelector `json:"passwordRef"`
+}
+
+// ConditionType represents a StepIssuer condition type.
+// +kubebuilder:validation:Enum=Ready
+type ConditionType string
+
+const (
+	// ConditionReady indicates that a StepIssuer is ready for use.
+	ConditionReady ConditionType = "Ready"
+)
+
+// ConditionStatus represents a condition's status.
+// +kubebuilder:validation:Enum=True;False;Unknown
+type ConditionStatus string
+
+// These are valid condition statuses. "ConditionTrue" means a resource is in
+// the condition; "ConditionFalse" means a resource is not in the condition;
+// "ConditionUnknown" means kubernetes can't decide if a resource is in the
+// condition or not. In the future, we could add other intermediate
+// conditions, e.g. ConditionDegraded.
+const (
+	// ConditionTrue represents the fact that a given condition is true
+	ConditionTrue ConditionStatus = "True"
+
+	// ConditionFalse represents the fact that a given condition is false
+	ConditionFalse ConditionStatus = "False"
+
+	// ConditionUnknown represents the fact that a given condition is unknown
+	ConditionUnknown ConditionStatus = "Unknown"
+)
+
+// StepIssuerCondition contains condition information for the step issuer.
+type StepIssuerCondition struct {
+	// Type of the condition, currently ('Ready').
+	Type ConditionType `json:"type"`
+
+	// Status of the condition, one of ('True', 'False', 'Unknown').
+	// +kubebuilder:validation:Enum=True;False;Unknown
+	Status ConditionStatus `json:"status"`
+
+	// LastTransitionTime is the timestamp corresponding to the last status
+	// change of this condition.
+	// +optional
+	LastTransitionTime *metav1.Time `json:"lastTransitionTime,omitempty"`
+
+	// Reason is a brief machine readable explanation for the condition's last
+	// transition.
+	// +optional
+	Reason string `json:"reason,omitempty"`
+
+	// Message is a human readable description of the details of the last
+	// transition, complementing reason.
+	// +optional
+	Message string `json:"message,omitempty"`
+}
diff --git a/api/v1beta1/zz_generated.deepcopy.go b/api/v1beta1/zz_generated.deepcopy.go
new file mode 100644
index 0000000..3e78740
--- /dev/null
+++ b/api/v1beta1/zz_generated.deepcopy.go
@@ -0,0 +1,178 @@
+// +build !ignore_autogenerated
+
+/*
+
+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.
+*/
+
+// autogenerated by controller-gen object, do not modify manually
+
+package v1beta1
+
+import (
+	"k8s.io/apimachinery/pkg/apis/meta/v1"
+	runtime "k8s.io/apimachinery/pkg/runtime"
+)
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *SecretKeySelector) DeepCopyInto(out *SecretKeySelector) {
+	*out = *in
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SecretKeySelector.
+func (in *SecretKeySelector) DeepCopy() *SecretKeySelector {
+	if in == nil {
+		return nil
+	}
+	out := new(SecretKeySelector)
+	in.DeepCopyInto(out)
+	return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *StepIssuer) DeepCopyInto(out *StepIssuer) {
+	*out = *in
+	out.TypeMeta = in.TypeMeta
+	in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
+	in.Spec.DeepCopyInto(&out.Spec)
+	in.Status.DeepCopyInto(&out.Status)
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StepIssuer.
+func (in *StepIssuer) DeepCopy() *StepIssuer {
+	if in == nil {
+		return nil
+	}
+	out := new(StepIssuer)
+	in.DeepCopyInto(out)
+	return out
+}
+
+// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
+func (in *StepIssuer) DeepCopyObject() runtime.Object {
+	if c := in.DeepCopy(); c != nil {
+		return c
+	}
+	return nil
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *StepIssuerCondition) DeepCopyInto(out *StepIssuerCondition) {
+	*out = *in
+	if in.LastTransitionTime != nil {
+		in, out := &in.LastTransitionTime, &out.LastTransitionTime
+		*out = new(v1.Time)
+		(*in).DeepCopyInto(*out)
+	}
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StepIssuerCondition.
+func (in *StepIssuerCondition) DeepCopy() *StepIssuerCondition {
+	if in == nil {
+		return nil
+	}
+	out := new(StepIssuerCondition)
+	in.DeepCopyInto(out)
+	return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *StepIssuerList) DeepCopyInto(out *StepIssuerList) {
+	*out = *in
+	out.TypeMeta = in.TypeMeta
+	in.ListMeta.DeepCopyInto(&out.ListMeta)
+	if in.Items != nil {
+		in, out := &in.Items, &out.Items
+		*out = make([]StepIssuer, len(*in))
+		for i := range *in {
+			(*in)[i].DeepCopyInto(&(*out)[i])
+		}
+	}
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StepIssuerList.
+func (in *StepIssuerList) DeepCopy() *StepIssuerList {
+	if in == nil {
+		return nil
+	}
+	out := new(StepIssuerList)
+	in.DeepCopyInto(out)
+	return out
+}
+
+// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
+func (in *StepIssuerList) DeepCopyObject() runtime.Object {
+	if c := in.DeepCopy(); c != nil {
+		return c
+	}
+	return nil
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *StepIssuerSpec) DeepCopyInto(out *StepIssuerSpec) {
+	*out = *in
+	out.Provisioner = in.Provisioner
+	if in.CABundle != nil {
+		in, out := &in.CABundle, &out.CABundle
+		*out = make([]byte, len(*in))
+		copy(*out, *in)
+	}
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StepIssuerSpec.
+func (in *StepIssuerSpec) DeepCopy() *StepIssuerSpec {
+	if in == nil {
+		return nil
+	}
+	out := new(StepIssuerSpec)
+	in.DeepCopyInto(out)
+	return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *StepIssuerStatus) DeepCopyInto(out *StepIssuerStatus) {
+	*out = *in
+	if in.Conditions != nil {
+		in, out := &in.Conditions, &out.Conditions
+		*out = make([]StepIssuerCondition, len(*in))
+		for i := range *in {
+			(*in)[i].DeepCopyInto(&(*out)[i])
+		}
+	}
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StepIssuerStatus.
+func (in *StepIssuerStatus) DeepCopy() *StepIssuerStatus {
+	if in == nil {
+		return nil
+	}
+	out := new(StepIssuerStatus)
+	in.DeepCopyInto(out)
+	return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *StepProvisioner) DeepCopyInto(out *StepProvisioner) {
+	*out = *in
+	out.PasswordRef = in.PasswordRef
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StepProvisioner.
+func (in *StepProvisioner) DeepCopy() *StepProvisioner {
+	if in == nil {
+		return nil
+	}
+	out := new(StepProvisioner)
+	in.DeepCopyInto(out)
+	return out
+}
diff --git a/config/crd/bases/certmanager.step.sm_stepissuers.yaml b/config/crd/bases/certmanager.step.sm_stepissuers.yaml
new file mode 100644
index 0000000..5afc93b
--- /dev/null
+++ b/config/crd/bases/certmanager.step.sm_stepissuers.yaml
@@ -0,0 +1,126 @@
+
+---
+apiVersion: apiextensions.k8s.io/v1beta1
+kind: CustomResourceDefinition
+metadata:
+  creationTimestamp: null
+  name: stepissuers.certmanager.step.sm
+spec:
+  group: certmanager.step.sm
+  names:
+    kind: StepIssuer
+    plural: stepissuers
+  scope: ""
+  validation:
+    openAPIV3Schema:
+      description: StepIssuer is the Schema for the stepissuers API
+      properties:
+        apiVersion:
+          description: 'APIVersion defines the versioned schema of this representation
+            of an object. Servers should convert recognized schemas to the latest
+            internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#resources'
+          type: string
+        kind:
+          description: 'Kind is a string value representing the REST resource this
+            object represents. Servers may infer this from the endpoint the client
+            submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds'
+          type: string
+        metadata:
+          type: object
+        spec:
+          description: StepIssuerSpec defines the desired state of StepIssuer
+          properties:
+            caBundle:
+              description: CABundle is a base64 encoded TLS certificate used to verify
+                connections to the step certificates server. If not set the system
+                root certificates are used to validate the TLS connection.
+              format: byte
+              type: string
+            provisioner:
+              description: Provisioner contains the step certificates provisioner
+                configuration.
+              properties:
+                kid:
+                  description: KeyID is the kid property of the JWK provisioner.
+                  type: string
+                name:
+                  description: Names is the name of the JWK provisioner.
+                  type: string
+                passwordRef:
+                  description: PasswordRef is a reference to a Secret containing the
+                    provisioner password used to decrypt the provisioner private key.
+                  properties:
+                    key:
+                      description: The key of the secret to select from. Must be a
+                        valid secret key.
+                      type: string
+                    name:
+                      description: The name of the secret in the pod's namespace to
+                        select from.
+                      type: string
+                  required:
+                  - name
+                  type: object
+              required:
+              - kid
+              - name
+              - passwordRef
+              type: object
+            url:
+              description: URL is the base URL for the step certificates instance.
+              type: string
+          required:
+          - provisioner
+          - url
+          type: object
+        status:
+          description: StepIssuerStatus defines the observed state of StepIssuer
+          properties:
+            conditions:
+              items:
+                description: StepIssuerCondition contains condition information for
+                  the step issuer.
+                properties:
+                  lastTransitionTime:
+                    description: LastTransitionTime is the timestamp corresponding
+                      to the last status change of this condition.
+                    format: date-time
+                    type: string
+                  message:
+                    description: Message is a human readable description of the details
+                      of the last transition, complementing reason.
+                    type: string
+                  reason:
+                    description: Reason is a brief machine readable explanation for
+                      the condition's last transition.
+                    type: string
+                  status:
+                    description: Status of the condition, one of ('True', 'False',
+                      'Unknown').
+                    enum:
+                    - "True"
+                    - "False"
+                    - Unknown
+                    type: string
+                  type:
+                    description: Type of the condition, currently ('Ready').
+                    enum:
+                    - Ready
+                    type: string
+                required:
+                - status
+                - type
+                type: object
+              type: array
+          type: object
+      type: object
+  versions:
+  - name: v1beta1
+    served: true
+    storage: true
+status:
+  acceptedNames:
+    kind: ""
+    plural: ""
+  conditions: []
+  storedVersions: []
diff --git a/config/crd/kustomization.yaml b/config/crd/kustomization.yaml
new file mode 100644
index 0000000..066a1ac
--- /dev/null
+++ b/config/crd/kustomization.yaml
@@ -0,0 +1,21 @@
+# This kustomization.yaml is not intended to be run by itself,
+# since it depends on service name and namespace that are out of this kustomize package.
+# It should be run by config/default
+resources:
+- bases/certmanager.step.sm_stepissuers.yaml
+# +kubebuilder:scaffold:crdkustomizeresource
+
+patches:
+# [WEBHOOK] To enable webhook, uncomment all the sections with [WEBHOOK] prefix.
+# patches here are for enabling the conversion webhook for each CRD
+#- patches/webhook_in_stepissuers.yaml
+# +kubebuilder:scaffold:crdkustomizewebhookpatch
+
+# [CERTMANAGER] To enable webhook, uncomment all the sections with [CERTMANAGER] prefix.
+# patches here are for enabling the CA injection for each CRD
+#- patches/cainjection_in_stepissuers.yaml
+# +kubebuilder:scaffold:crdkustomizecainjectionpatch
+
+# the following config is for teaching kustomize how to do kustomization for CRDs.
+configurations:
+- kustomizeconfig.yaml
diff --git a/config/crd/kustomizeconfig.yaml b/config/crd/kustomizeconfig.yaml
new file mode 100644
index 0000000..6f83d9a
--- /dev/null
+++ b/config/crd/kustomizeconfig.yaml
@@ -0,0 +1,17 @@
+# This file is for teaching kustomize how to substitute name and namespace reference in CRD
+nameReference:
+- kind: Service
+  version: v1
+  fieldSpecs:
+  - kind: CustomResourceDefinition
+    group: apiextensions.k8s.io
+    path: spec/conversion/webhookClientConfig/service/name
+
+namespace:
+- kind: CustomResourceDefinition
+  group: apiextensions.k8s.io
+  path: spec/conversion/webhookClientConfig/service/namespace
+  create: false
+
+varReference:
+- path: metadata/annotations
diff --git a/config/crd/patches/cainjection_in_stepissuers.yaml b/config/crd/patches/cainjection_in_stepissuers.yaml
new file mode 100644
index 0000000..9c89961
--- /dev/null
+++ b/config/crd/patches/cainjection_in_stepissuers.yaml
@@ -0,0 +1,8 @@
+# The following patch adds a directive for certmanager to inject CA into the CRD
+# CRD conversion requires k8s 1.13 or later.
+apiVersion: apiextensions.k8s.io/v1beta1
+kind: CustomResourceDefinition
+metadata:
+  annotations:
+    certmanager.k8s.io/inject-ca-from: $(CERTIFICATE_NAMESPACE)/$(CERTIFICATE_NAME)
+  name: stepissuers.certmanager.step.sm
diff --git a/config/crd/patches/webhook_in_stepissuers.yaml b/config/crd/patches/webhook_in_stepissuers.yaml
new file mode 100644
index 0000000..745ec1c
--- /dev/null
+++ b/config/crd/patches/webhook_in_stepissuers.yaml
@@ -0,0 +1,17 @@
+# The following patch enables conversion webhook for CRD
+# CRD conversion requires k8s 1.13 or later.
+apiVersion: apiextensions.k8s.io/v1beta1
+kind: CustomResourceDefinition
+metadata:
+  name: stepissuers.certmanager.step.sm
+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)
+      caBundle: Cg==
+      service:
+        namespace: system
+        name: webhook-service
+        path: /convert
diff --git a/config/rbac/role.yaml b/config/rbac/role.yaml
new file mode 100644
index 0000000..9cb0d26
--- /dev/null
+++ b/config/rbac/role.yaml
@@ -0,0 +1,45 @@
+
+---
+apiVersion: rbac.authorization.k8s.io/v1
+kind: ClusterRole
+metadata:
+  creationTimestamp: null
+  name: manager-role
+rules:
+- apiGroups:
+  - certmanager.k8s.io
+  resources:
+  - certificaterequests
+  verbs:
+  - get
+  - list
+  - update
+  - watch
+- apiGroups:
+  - certmanager.k8s.io
+  resources:
+  - certificaterequests/status
+  verbs:
+  - get
+  - patch
+  - update
+- apiGroups:
+  - certmanager.step.sm
+  resources:
+  - stepissuers
+  verbs:
+  - create
+  - delete
+  - get
+  - list
+  - patch
+  - update
+  - watch
+- apiGroups:
+  - certmanager.step.sm
+  resources:
+  - stepissuers/status
+  verbs:
+  - get
+  - patch
+  - update
diff --git a/config/webhook/manifests.yaml b/config/webhook/manifests.yaml
new file mode 100644
index 0000000..e69de29
-- 
GitLab