Skip to content

Commit

Permalink
Self signed issuer (#228)
Browse files Browse the repository at this point in the history
* implement selfSigned issuer

* enable cert duration for ca issuer

* enable cert duration for acme issuer

* checks for isCA and duration

* set requests per day to MaxInt for CA and self-signed issuer

* Update pkg/controller/issuer/ca/handler.go

Co-authored-by: Martin Weindel <martin.weindel@sap.com>

* chore: Remove obsolete script format.sh

* style: Run `make format`

* fix: Resolve mishaps from rebase

* style: Add trailing newline

* fix: Dereference duration pointer

* refactor: Rename multipleIssuerTypes to hasMultipleIssuerTypes

* chore: Fix typo in comment

* fix: Check against nil Duration pointer

* fix: Check against nil Duration pointer

* chore: Fix typo in comment

* test: Add self-signed controller unit tests

* test: Add certificate controller unit tests

* test: Add issuer info unit test

* test: Add PKI unit tests

* test: Add certificate unit tests

* chore: Use proper assertion HaveCap()

* style: Format Go imports

* chore: Add missing license headers

* test: Wrap ACME issuer test in context

* test: Integration test for self-signed certificates

* test: Structure self-signed certificate unit test

* style: Add period after comment (PR review)

* style: Add period after comment (PR review)

* style: Add period after comment (PR review)

* test: Fix test name (PR review)

* test: Assert private key size properly (PR review)

* test: Assert private key size (PR review)

---------

Co-authored-by: Martin Weindel <martin.weindel@sap.com>
Co-authored-by: Marc Vornetran <marc.vornetran@sap.com>
  • Loading branch information
3 people authored Nov 26, 2024
1 parent b094e0f commit e224d15
Show file tree
Hide file tree
Showing 29 changed files with 901 additions and 73 deletions.
68 changes: 65 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -143,11 +143,13 @@ is already in place. The operator must request/provide by its own means a CA
or an intermediate CA. This is mainly used for **on-premises** and
**airgapped** environements.

It can also be used for **developement** or **testing** purproses. In this case
a Self-signed Certificate Authority can be created by following the section below.
To create a self-signed certificate a dedicated issuer of type [selfSigned](#selfsigned) should be used.

_Create a Self-signed Certificate Authority (optional)_
It is also possible to manually create a self-signed certificate using the CA issuer
<details>
<summary>Manual steps</summary>

Create a Self-signed Certificate Authority
```bash
▶ openssl genrsa -out CA-key.pem 4096
▶ export CONFIG="
Expand Down Expand Up @@ -244,6 +246,66 @@ Some details about the CA can be found in the status of the issuer.
"type": "ca"
}
```
</details>

### SelfSigned
This issuer is meant to be used when you want to create a fully managed self-signed certificate.

Configure your shoot to allow custom issuers in the shoot cluster. By default, issuers are created in the control plane of your cluster.
```yaml
kind: Shoot
...
spec:
extensions:
- type: shoot-cert-service
providerConfig:
apiVersion: service.cert.extensions.gardener.cloud/v1alpha1
kind: CertConfig
shootIssuers:
enabled: true # if true, allows to specify issuers in the shoot cluster
...
```

Create and deploy a self-signed issuer in your shoot cluster ([examples/20-issuer-selfsigned.yaml](./examples/20-issuer-selfsigned.yaml))
```yaml
apiVersion: cert.gardener.cloud/v1alpha1
kind: Issuer
metadata:
name: issuer-selfsigned
namespace: default
spec:
selfSigned: {}
```

Create a certificate ([examples/30-cert-selfsigned.yaml](./examples/30-cert-selfsigned.yaml)).
Please note that `spec.isCA` must be set to `true` to create a self-signed certificate. The duration (life-time) of the certificate
as well as the private key algorithm and key size may be specified. Duration value must be in units accepted by Go `time.ParseDuration`
([see here](https://golang.org/pkg/time/#ParseDurationThe)), and it must be greater than 720h (30 days).
```yaml
apiVersion: cert.gardener.cloud/v1alpha1
kind: Certificate
metadata:
name: cert-selfsigned
namespace: default
spec:
commonName: cert1.mydomain.com
isCA: true
# optional: default is 90 days (2160h). Must be greater 30 days (720h)
# duration: 720h1m
# optional defaults to RSA 2048
#privateKey:
# algorithm: ECDSA
# size: 384
issuerRef:
name: issuer-selfsigned
namespace: default # must be specified when issuer runs in shoot!
# optional: secret where the certificate should be stored
#secretRef:
# name: cert-selfsigned-foo
# namespace: default
```


## Requesting a Certificate

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,12 @@ spec:
is used if CNAME record for DNS01 challange domain `_acme-challenge.<domain>`
is set.
type: boolean
isCA:
description: |-
IsCA value is used to set the `isCA` field on the certificate request.
Note that the issuer may choose to ignore the requested isCA value, just
like any other requested attribute.
type: boolean
issuerRef:
description: IssuerRef is the reference of the issuer to use.
properties:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,9 @@ spec:
description: RequestsPerDayQuota is the maximum number of certificate
requests per days allowed for this issuer
type: integer
selfSigned:
description: SelfSigned is the self signed specific spec.
type: object
type: object
status:
description: IssuerStatus is the status of the issuer.
Expand Down Expand Up @@ -209,8 +212,8 @@ spec:
description: State is either empty, 'Pending', 'Error', or 'Ready'.
type: string
type:
description: Type is the issuer type. Currently only 'acme' and 'ca'
are supported.
description: Type is the issuer type. Currently only 'acme', 'ca'
and 'selfSigned' are supported.
type: string
required:
- state
Expand Down
7 changes: 7 additions & 0 deletions examples/20-issuer-selfsigned.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
apiVersion: cert.gardener.cloud/v1alpha1
kind: Issuer
metadata:
name: issuer-selfsigned
namespace: default
spec:
selfSigned: {}
23 changes: 23 additions & 0 deletions examples/30-cert-selfsigned.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
apiVersion: cert.gardener.cloud/v1alpha1
kind: Certificate
metadata:
name: cert-selfsigned
namespace: default
spec:
commonName: ca1.mydomain.com
isCA: true
# optional: default is 90 days (2160h). Must be greater 2*30 days (1440h)
# duration: 1441h
# optional defaults to RSA 2048
# privateKey:
# algorithm: ECDSA
# size: 384
# CSR can also be specified
# csr: ...
issuerRef:
name: issuer-selfsigned
namespace: default # must be specified when issuer runs in shoot!
# optional: secret where the certificate should be stored
#secretRef:
# name: cert-selfsigned-foo
# namespace: default
6 changes: 6 additions & 0 deletions pkg/apis/cert/crds/cert.gardener.cloud_certificates.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,12 @@ spec:
is used if CNAME record for DNS01 challange domain `_acme-challenge.<domain>`
is set.
type: boolean
isCA:
description: |-
IsCA value is used to set the `isCA` field on the certificate request.
Note that the issuer may choose to ignore the requested isCA value, just
like any other requested attribute.
type: boolean
issuerRef:
description: IssuerRef is the reference of the issuer to use.
properties:
Expand Down
7 changes: 5 additions & 2 deletions pkg/apis/cert/crds/cert.gardener.cloud_issuers.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,9 @@ spec:
description: RequestsPerDayQuota is the maximum number of certificate
requests per days allowed for this issuer
type: integer
selfSigned:
description: SelfSigned is the self signed specific spec.
type: object
type: object
status:
description: IssuerStatus is the status of the issuer.
Expand Down Expand Up @@ -204,8 +207,8 @@ spec:
description: State is either empty, 'Pending', 'Error', or 'Ready'.
type: string
type:
description: Type is the issuer type. Currently only 'acme' and 'ca'
are supported.
description: Type is the issuer type. Currently only 'acme', 'ca'
and 'selfSigned' are supported.
type: string
required:
- state
Expand Down
13 changes: 11 additions & 2 deletions pkg/apis/cert/crds/zz_generated_crds.go
Original file line number Diff line number Diff line change
Expand Up @@ -407,6 +407,12 @@ spec:
is used if CNAME record for DNS01 challange domain ` + "`" + `_acme-challenge.<domain>` + "`" + `
is set.
type: boolean
isCA:
description: |-
IsCA value is used to set the ` + "`" + `isCA` + "`" + ` field on the certificate request.
Note that the issuer may choose to ignore the requested isCA value, just
like any other requested attribute.
type: boolean
issuerRef:
description: IssuerRef is the reference of the issuer to use.
properties:
Expand Down Expand Up @@ -875,6 +881,9 @@ spec:
description: RequestsPerDayQuota is the maximum number of certificate
requests per days allowed for this issuer
type: integer
selfSigned:
description: SelfSigned is the self signed specific spec.
type: object
type: object
status:
description: IssuerStatus is the status of the issuer.
Expand Down Expand Up @@ -903,8 +912,8 @@ spec:
description: State is either empty, 'Pending', 'Error', or 'Ready'.
type: string
type:
description: Type is the issuer type. Currently only 'acme' and 'ca'
are supported.
description: Type is the issuer type. Currently only 'acme', 'ca'
and 'selfSigned' are supported.
type: string
required:
- state
Expand Down
14 changes: 13 additions & 1 deletion pkg/apis/cert/v1alpha1/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,11 @@ type CertificateSpec struct {
// Private key options. These include the key algorithm and size.
// +optional
PrivateKey *CertificatePrivateKey `json:"privateKey,omitempty"`
// IsCA value is used to set the `isCA` field on the certificate request.
// Note that the issuer may choose to ignore the requested isCA value, just
// like any other requested attribute.
// +optional
IsCA *bool `json:"isCA,omitempty"`
// Requested 'duration' (i.e. lifetime) of the Certificate. Note that the
// ACME issuer may choose to ignore the requested duration, just like any other
// requested attribute.
Expand Down Expand Up @@ -406,6 +411,9 @@ type IssuerSpec struct {
// CA is the CA specific spec.
// +optional
CA *CASpec `json:"ca,omitempty"`
// SelfSigned is the self signed specific spec.
// +optional
SelfSigned *SelfSignedSpec `json:"selfSigned,omitempty"`
// RequestsPerDayQuota is the maximum number of certificate requests per days allowed for this issuer
// +optional
RequestsPerDayQuota *int `json:"requestsPerDayQuota,omitempty"`
Expand Down Expand Up @@ -475,6 +483,10 @@ type CASpec struct {
PrivateKeySecretRef *corev1.SecretReference `json:"privateKeySecretRef,omitempty"`
}

// SelfSignedSpec is the self signed specific spec.
type SelfSignedSpec struct {
}

// IssuerStatus is the status of the issuer.
type IssuerStatus struct {
// ObservedGeneration is the observed generation of the spec.
Expand All @@ -484,7 +496,7 @@ type IssuerStatus struct {
// Message is the status or error message.
// +optional
Message *string `json:"message,omitempty"`
// Type is the issuer type. Currently only 'acme' and 'ca' are supported.
// Type is the issuer type. Currently only 'acme', 'ca' and 'selfSigned' are supported.
// +optional
Type *string `json:"type"`
// ACME is the ACME specific status.
Expand Down
26 changes: 26 additions & 0 deletions pkg/apis/cert/v1alpha1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit e224d15

Please sign in to comment.