change wording on descriptions for Vault and TPP 'CABundle' fields

Clarifies language a little; makes it clearer that the bundle
should be base64 encoded. Previously it was slightly confusing
in that PEM certificates are themselves base64 encoded.

Also makes it clearer what our CABundle validation does and does not do
by adding a standalone validation function and tweaking the error
message for an invalid CA bundle.

Also updates validation to not print CA bundle for Vault issuer when the
bundle is invalid, since it won't help with debugging anything.
Currently the bundle is printed as byte values ("0x32, 0x58, 0x43...")
and in any case printing the whole bundle could be noisy if it's large

Signed-off-by: Ashley Davis <ashley.davis@jetstack.io>
This commit is contained in:
Ashley Davis 2022-12-15 11:35:58 +00:00
parent 6806035cb7
commit f68693bb6a
No known key found for this signature in database
GPG Key ID: DD14CC017E32BEB1
10 changed files with 117 additions and 100 deletions

View File

@ -1156,11 +1156,11 @@ spec:
description: 'Name of the resource being referred to. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names'
type: string
caBundle:
description: PEM-encoded CA bundle (base64-encoded) used to validate Vault server certificate. Only used if the Server URL is using HTTPS protocol. This parameter is ignored for plain HTTP protocol connection. If not set the system root certificates are used to validate the TLS connection. Mutually exclusive with CABundleSecretRef. If neither CABundle nor CABundleSecretRef are defined, the cert-manager controller system root certificates are used to validate the TLS connection.
description: Base64-encoded bundle of PEM CAs which will be used to validate the certificate chain presented by Vault. Only used if using HTTPS to connect to Vault and ignored for HTTP connections. Mutually exclusive with CABundleSecretRef. If neither CABundle nor CABundleSecretRef are defined, the certificate bundle in the cert-manager controller container is used to validate the TLS connection.
type: string
format: byte
caBundleSecretRef:
description: CABundleSecretRef is a reference to a Secret which contains the CABundle which will be used when connecting to Vault when using HTTPS. Mutually exclusive with CABundle. If neither CABundleSecretRef nor CABundle are defined, the cert-manager controller system root certificates are used to validate the TLS connection. If no key for the Secret is specified, cert-manager will default to 'ca.crt'.
description: Reference to a Secret containing a bundle of PEM-encoded CAs to use when verifying the certificate chain presented by Vault when using HTTPS. Mutually exclusive with CABundle. If neither CABundle nor CABundleSecretRef are defined, the certificate bundle in the cert-manager controller container is used to validate the TLS connection. If no key for the Secret is specified, cert-manager will default to 'ca.crt'.
type: object
required:
- name
@ -1215,7 +1215,7 @@ spec:
- url
properties:
caBundle:
description: CABundle is a PEM encoded TLS certificate to use to verify connections to the TPP instance. If specified, system roots will not be used and the issuing CA for the TPP instance must be verifiable using the provided root. If not specified, the connection will be verified using the cert-manager system root certificates.
description: Base64-encoded bundle of PEM CAs which will be used to validate the certificate chain presented by the TPP server. Only used if using HTTPS; ignored for HTTP. If undefined, the certificate bundle in the cert-manager controller container is used to validate the chain.
type: string
format: byte
credentialsRef:

View File

@ -1156,11 +1156,11 @@ spec:
description: 'Name of the resource being referred to. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names'
type: string
caBundle:
description: PEM-encoded CA bundle (base64-encoded) used to validate Vault server certificate. Only used if the Server URL is using HTTPS protocol. This parameter is ignored for plain HTTP protocol connection. If not set the system root certificates are used to validate the TLS connection. Mutually exclusive with CABundleSecretRef. If neither CABundle nor CABundleSecretRef are defined, the cert-manager controller system root certificates are used to validate the TLS connection.
description: Base64-encoded bundle of PEM CAs which will be used to validate the certificate chain presented by Vault. Only used if using HTTPS to connect to Vault and ignored for HTTP connections. Mutually exclusive with CABundleSecretRef. If neither CABundle nor CABundleSecretRef are defined, the certificate bundle in the cert-manager controller container is used to validate the TLS connection.
type: string
format: byte
caBundleSecretRef:
description: CABundleSecretRef is a reference to a Secret which contains the CABundle which will be used when connecting to Vault when using HTTPS. Mutually exclusive with CABundle. If neither CABundleSecretRef nor CABundle are defined, the cert-manager controller system root certificates are used to validate the TLS connection. If no key for the Secret is specified, cert-manager will default to 'ca.crt'.
description: Reference to a Secret containing a bundle of PEM-encoded CAs to use when verifying the certificate chain presented by Vault when using HTTPS. Mutually exclusive with CABundle. If neither CABundle nor CABundleSecretRef are defined, the certificate bundle in the cert-manager controller container is used to validate the TLS connection. If no key for the Secret is specified, cert-manager will default to 'ca.crt'.
type: object
required:
- name
@ -1215,7 +1215,7 @@ spec:
- url
properties:
caBundle:
description: CABundle is a PEM encoded TLS certificate to use to verify connections to the TPP instance. If specified, system roots will not be used and the issuing CA for the TPP instance must be verifiable using the provided root. If not specified, the connection will be verified using the cert-manager system root certificates.
description: Base64-encoded bundle of PEM CAs which will be used to validate the certificate chain presented by the TPP server. Only used if using HTTPS; ignored for HTTP. If undefined, the certificate bundle in the cert-manager controller container is used to validate the chain.
type: string
format: byte
credentialsRef:

View File

@ -137,12 +137,10 @@ type VenafiTPP struct {
// The secret must contain two keys, 'username' and 'password'.
CredentialsRef cmmeta.LocalObjectReference
// CABundle is a PEM encoded TLS certificate to use to verify connections to
// the TPP instance.
// If specified, system roots will not be used and the issuing CA for the
// TPP instance must be verifiable using the provided root.
// If not specified, the connection will be verified using the cert-manager
// system root certificates.
// Base64-encoded bundle of PEM CAs which will be used to validate the certificate
// chain presented by the TPP server. Only used if using HTTPS; ignored for HTTP.
// If undefined, the certificate bundle in the cert-manager controller container
// is used to validate the chain.
CABundle []byte
}
@ -182,19 +180,20 @@ type VaultIssuer struct {
// More about namespaces can be found here https://www.vaultproject.io/docs/enterprise/namespaces
Namespace string
// PEM-encoded CA bundle (base64-encoded) used to validate Vault server
// certificate. Only used if the Server URL is using HTTPS protocol. This
// parameter is ignored for plain HTTP protocol connection. If not set the
// system root certificates are used to validate the TLS connection.
// Mutually exclusive with CABundleSecretRef. If neither CABundle nor CABundleSecretRef are defined,
// the cert-manager controller system root certificates are used to validate the TLS connection.
// Base64-encoded bundle of PEM CAs which will be used to validate the certificate
// chain presented by Vault. Only used if using HTTPS to connect to Vault and
// ignored for HTTP connections.
// Mutually exclusive with CABundleSecretRef.
// If neither CABundle nor CABundleSecretRef are defined, the certificate bundle in
// the cert-manager controller container is used to validate the TLS connection.
// +optional
CABundle []byte
// CABundleSecretRef is a reference to a Secret which contains the CABundle which will be used when
// connecting to Vault when using HTTPS.
// Mutually exclusive with CABundle. If neither CABundleSecretRef nor CABundle are defined, the cert-manager
// controller system root certificates are used to validate the TLS connection.
// Reference to a Secret containing a bundle of PEM-encoded CAs to use when
// verifying the certificate chain presented by Vault when using HTTPS.
// Mutually exclusive with CABundle.
// If neither CABundle nor CABundleSecretRef are defined, the certificate bundle in
// the cert-manager controller container is used to validate the TLS connection.
// If no key for the Secret is specified, cert-manager will default to 'ca.crt'.
// +optional
CABundleSecretRef *cmmeta.SecretKeySelector

View File

@ -150,12 +150,10 @@ type VenafiTPP struct {
// The secret must contain two keys, 'username' and 'password'.
CredentialsRef cmmeta.LocalObjectReference `json:"credentialsRef"`
// CABundle is a PEM encoded TLS certificate to use to verify connections to
// the TPP instance.
// If specified, system roots will not be used and the issuing CA for the
// TPP instance must be verifiable using the provided root.
// If not specified, the connection will be verified using the cert-manager
// system root certificates.
// Base64-encoded bundle of PEM CAs which will be used to validate the certificate
// chain presented by the TPP server. Only used if using HTTPS; ignored for HTTP.
// If undefined, the certificate bundle in the cert-manager controller container
// is used to validate the chain.
// +optional
CABundle []byte `json:"caBundle,omitempty"`
}
@ -199,19 +197,20 @@ type VaultIssuer struct {
// +optional
Namespace string `json:"namespace,omitempty"`
// PEM-encoded CA bundle (base64-encoded) used to validate Vault server
// certificate. Only used if the Server URL is using HTTPS protocol. This
// parameter is ignored for plain HTTP protocol connection. If not set the
// system root certificates are used to validate the TLS connection.
// Mutually exclusive with CABundleSecretRef. If neither CABundle nor CABundleSecretRef are defined,
// the cert-manager controller system root certificates are used to validate the TLS connection.
// Base64-encoded bundle of PEM CAs which will be used to validate the certificate
// chain presented by Vault. Only used if using HTTPS to connect to Vault and
// ignored for HTTP connections.
// Mutually exclusive with CABundleSecretRef.
// If neither CABundle nor CABundleSecretRef are defined, the certificate bundle in
// the cert-manager controller container is used to validate the TLS connection.
// +optional
CABundle []byte `json:"caBundle,omitempty"`
// CABundleSecretRef is a reference to a Secret which contains the CABundle which will be used when
// connecting to Vault when using HTTPS.
// Mutually exclusive with CABundle. If neither CABundleSecretRef nor CABundle are defined, the cert-manager
// controller system root certificates are used to validate the TLS connection.
// Reference to a Secret containing a bundle of PEM-encoded CAs to use when
// verifying the certificate chain presented by Vault when using HTTPS.
// Mutually exclusive with CABundle.
// If neither CABundle nor CABundleSecretRef are defined, the certificate bundle in
// the cert-manager controller container is used to validate the TLS connection.
// If no key for the Secret is specified, cert-manager will default to 'ca.crt'.
// +optional
CABundleSecretRef *cmmeta.SecretKeySelector `json:"caBundleSecretRef,omitempty"`

View File

@ -150,12 +150,10 @@ type VenafiTPP struct {
// The secret must contain two keys, 'username' and 'password'.
CredentialsRef cmmeta.LocalObjectReference `json:"credentialsRef"`
// CABundle is a PEM encoded TLS certificate to use to verify connections to
// the TPP instance.
// If specified, system roots will not be used and the issuing CA for the
// TPP instance must be verifiable using the provided root.
// If not specified, the connection will be verified using the cert-manager
// system root certificates.
// Base64-encoded bundle of PEM CAs which will be used to validate the certificate
// chain presented by the TPP server. Only used if using HTTPS; ignored for HTTP.
// If undefined, the certificate bundle in the cert-manager controller container
// is used to validate the chain.
// +optional
CABundle []byte `json:"caBundle,omitempty"`
}
@ -199,19 +197,20 @@ type VaultIssuer struct {
// +optional
Namespace string `json:"namespace,omitempty"`
// PEM-encoded CA bundle (base64-encoded) used to validate Vault server
// certificate. Only used if the Server URL is using HTTPS protocol. This
// parameter is ignored for plain HTTP protocol connection. If not set the
// system root certificates are used to validate the TLS connection.
// Mutually exclusive with CABundleSecretRef. If neither CABundle nor CABundleSecretRef are defined,
// the cert-manager controller system root certificates are used to validate the TLS connection.
// Base64-encoded bundle of PEM CAs which will be used to validate the certificate
// chain presented by Vault. Only used if using HTTPS to connect to Vault and
// ignored for HTTP connections.
// Mutually exclusive with CABundleSecretRef.
// If neither CABundle nor CABundleSecretRef are defined, the certificate bundle in
// the cert-manager controller container is used to validate the TLS connection.
// +optional
CABundle []byte `json:"caBundle,omitempty"`
// CABundleSecretRef is a reference to a Secret which contains the CABundle which will be used when
// connecting to Vault when using HTTPS.
// Mutually exclusive with CABundle. If neither CABundleSecretRef nor CABundle are defined, the cert-manager
// controller system root certificates are used to validate the TLS connection.
// Reference to a Secret containing a bundle of PEM-encoded CAs to use when
// verifying the certificate chain presented by Vault when using HTTPS.
// Mutually exclusive with CABundle.
// If neither CABundle nor CABundleSecretRef are defined, the certificate bundle in
// the cert-manager controller container is used to validate the TLS connection.
// If no key for the Secret is specified, cert-manager will default to 'ca.crt'.
// +optional
CABundleSecretRef *cmmeta.SecretKeySelector `json:"caBundleSecretRef,omitempty"`

View File

@ -152,12 +152,10 @@ type VenafiTPP struct {
// The secret must contain two keys, 'username' and 'password'.
CredentialsRef cmmeta.LocalObjectReference `json:"credentialsRef"`
// CABundle is a PEM encoded TLS certificate to use to verify connections to
// the TPP instance.
// If specified, system roots will not be used and the issuing CA for the
// TPP instance must be verifiable using the provided root.
// If not specified, the connection will be verified using the cert-manager
// system root certificates.
// Base64-encoded bundle of PEM CAs which will be used to validate the certificate
// chain presented by the TPP server. Only used if using HTTPS; ignored for HTTP.
// If undefined, the certificate bundle in the cert-manager controller container
// is used to validate the chain.
// +optional
CABundle []byte `json:"caBundle,omitempty"`
}
@ -201,19 +199,20 @@ type VaultIssuer struct {
// +optional
Namespace string `json:"namespace,omitempty"`
// PEM-encoded CA bundle (base64-encoded) used to validate Vault server
// certificate. Only used if the Server URL is using HTTPS protocol. This
// parameter is ignored for plain HTTP protocol connection. If not set the
// system root certificates are used to validate the TLS connection.
// Mutually exclusive with CABundleSecretRef. If neither CABundle nor CABundleSecretRef are defined,
// the cert-manager controller system root certificates are used to validate the TLS connection.
// Base64-encoded bundle of PEM CAs which will be used to validate the certificate
// chain presented by Vault. Only used if using HTTPS to connect to Vault and
// ignored for HTTP connections.
// Mutually exclusive with CABundleSecretRef.
// If neither CABundle nor CABundleSecretRef are defined, the certificate bundle in
// the cert-manager controller container is used to validate the TLS connection.
// +optional
CABundle []byte `json:"caBundle,omitempty"`
// CABundleSecretRef is a reference to a Secret which contains the CABundle which will be used when
// connecting to Vault when using HTTPS.
// Mutually exclusive with CABundle. If neither CABundleSecretRef nor CABundle are defined, the cert-manager
// controller system root certificates are used to validate the TLS connection.
// Reference to a Secret containing a bundle of PEM-encoded CAs to use when
// verifying the certificate chain presented by Vault when using HTTPS.
// Mutually exclusive with CABundle.
// If neither CABundle nor CABundleSecretRef are defined, the certificate bundle in
// the cert-manager controller container is used to validate the TLS connection.
// If no key for the Secret is specified, cert-manager will default to 'ca.crt'.
// +optional
CABundleSecretRef *cmmeta.SecretKeySelector `json:"caBundleSecretRef,omitempty"`

View File

@ -226,36 +226,40 @@ func ValidateSelfSignedIssuerConfig(iss *certmanager.SelfSignedIssuer, fldPath *
func ValidateVaultIssuerConfig(iss *certmanager.VaultIssuer, fldPath *field.Path) field.ErrorList {
el := field.ErrorList{}
if len(iss.Server) == 0 {
el = append(el, field.Required(fldPath.Child("server"), ""))
}
if len(iss.Path) == 0 {
el = append(el, field.Required(fldPath.Child("path"), ""))
}
// check if caBundle is valid
certs := iss.CABundle
if len(certs) > 0 {
caCertPool := x509.NewCertPool()
ok := caCertPool.AppendCertsFromPEM(certs)
if !ok {
el = append(el, field.Invalid(fldPath.Child("caBundle"), "", "Specified CA bundle is invalid"))
if len(iss.CABundle) > 0 {
if err := validateCABundleNotEmpty(iss.CABundle); err != nil {
el = append(el, field.Invalid(fldPath.Child("caBundle"), "<snip>", err.Error()))
}
}
if len(iss.CABundle) > 0 && iss.CABundleSecretRef != nil {
el = append(el, field.Invalid(fldPath.Child("caBundle"), iss.CABundle, "specified caBundle and caBundleSecretRef cannot be used together"))
// We don't use iss.CABundle for the "value interface{}" argument to field.Invalid for caBundle
// since printing the whole bundle verbatim won't help diagnose any issues
el = append(el, field.Invalid(fldPath.Child("caBundle"), "<snip>", "specified caBundle and caBundleSecretRef cannot be used together"))
el = append(el, field.Invalid(fldPath.Child("caBundleSecretRef"), iss.CABundleSecretRef.Name, "specified caBundleSecretRef and caBundle cannot be used together"))
}
return el
// TODO: add validation for Vault authentication types
return el
}
func ValidateVenafiTPP(tpp *certmanager.VenafiTPP, fldPath *field.Path) (el field.ErrorList) {
if tpp.URL == "" {
el = append(el, field.Required(fldPath.Child("url"), ""))
}
// TODO: validate CABundle using validateCABundleNotEmpty
return el
}
@ -500,3 +504,22 @@ func ValidateSecretKeySelector(sks *cmmeta.SecretKeySelector, fldPath *field.Pat
}
return el
}
// validateCABundleNotEmpty performs a soft check on the CA bundle to see if there's at least one
// valid CA certificate inside.
// This uses the standard library crypto/x509.CertPool.AppendCertsFromPEM function, which
// skips over invalid certificates rather than rejecting them.
func validateCABundleNotEmpty(bundle []byte) error {
// TODO: Change this function to actually validate certificates so that invalid certs
// are rejected or at least warned on.
// For example, something like: https://github.com/cert-manager/trust-manager/blob/21c839ff1128990e049eaf23000a9a8d6716c89e/pkg/util/pem.go#L26-L81
pool := x509.NewCertPool()
ok := pool.AppendCertsFromPEM(bundle)
if !ok {
return fmt.Errorf("cert bundle didn't contain any valid certificates")
}
return nil
}

View File

@ -88,7 +88,7 @@ func TestValidateVaultIssuerConfig(t *testing.T) {
},
},
errs: []*field.Error{
field.Invalid(fldPath.Child("caBundle"), caBundle, "specified caBundle and caBundleSecretRef cannot be used together"),
field.Invalid(fldPath.Child("caBundle"), "<snip>", "specified caBundle and caBundleSecretRef cannot be used together"),
field.Invalid(fldPath.Child("caBundleSecretRef"), "test-secret", "specified caBundleSecretRef and caBundle cannot be used together"),
},
},
@ -102,14 +102,14 @@ func TestValidateVaultIssuerConfig(t *testing.T) {
field.Required(fldPath.Child("path"), ""),
},
},
"vault issuer with invalid fields": {
"vault issuer with a CA bundle containing no valid certificates": {
spec: &cmapi.VaultIssuer{
Server: "something",
Path: "a/b/c",
CABundle: []byte("invalid"),
},
errs: []*field.Error{
field.Invalid(fldPath.Child("caBundle"), "", "Specified CA bundle is invalid"),
field.Invalid(fldPath.Child("caBundle"), "<snip>", "cert bundle didn't contain any valid certificates"),
},
},
}

View File

@ -154,12 +154,10 @@ type VenafiTPP struct {
// The secret must contain two keys, 'username' and 'password'.
CredentialsRef cmmeta.LocalObjectReference `json:"credentialsRef"`
// CABundle is a PEM encoded TLS certificate to use to verify connections to
// the TPP instance.
// If specified, system roots will not be used and the issuing CA for the
// TPP instance must be verifiable using the provided root.
// If not specified, the connection will be verified using the cert-manager
// system root certificates.
// Base64-encoded bundle of PEM CAs which will be used to validate the certificate
// chain presented by the TPP server. Only used if using HTTPS; ignored for HTTP.
// If undefined, the certificate bundle in the cert-manager controller container
// is used to validate the chain.
// +optional
CABundle []byte `json:"caBundle,omitempty"`
}
@ -203,19 +201,20 @@ type VaultIssuer struct {
// +optional
Namespace string `json:"namespace,omitempty"`
// PEM-encoded CA bundle (base64-encoded) used to validate Vault server
// certificate. Only used if the Server URL is using HTTPS protocol. This
// parameter is ignored for plain HTTP protocol connection. If not set the
// system root certificates are used to validate the TLS connection.
// Mutually exclusive with CABundleSecretRef. If neither CABundle nor CABundleSecretRef are defined,
// the cert-manager controller system root certificates are used to validate the TLS connection.
// Base64-encoded bundle of PEM CAs which will be used to validate the certificate
// chain presented by Vault. Only used if using HTTPS to connect to Vault and
// ignored for HTTP connections.
// Mutually exclusive with CABundleSecretRef.
// If neither CABundle nor CABundleSecretRef are defined, the certificate bundle in
// the cert-manager controller container is used to validate the TLS connection.
// +optional
CABundle []byte `json:"caBundle,omitempty"`
// CABundleSecretRef is a reference to a Secret which contains the CABundle which will be used when
// connecting to Vault when using HTTPS.
// Mutually exclusive with CABundle. If neither CABundleSecretRef nor CABundle are defined, the cert-manager
// controller system root certificates are used to validate the TLS connection.
// Reference to a Secret containing a bundle of PEM-encoded CAs to use when
// verifying the certificate chain presented by Vault when using HTTPS.
// Mutually exclusive with CABundle.
// If neither CABundle nor CABundleSecretRef are defined, the certificate bundle in
// the cert-manager controller container is used to validate the TLS connection.
// If no key for the Secret is specified, cert-manager will default to 'ca.crt'.
// +optional
CABundleSecretRef *cmmeta.SecretKeySelector `json:"caBundleSecretRef,omitempty"`

View File

@ -233,8 +233,7 @@ var _ = framework.CertManagerDescribe("Vault Issuer", func() {
_, err := f.CertManagerClientSet.CertmanagerV1().Issuers(f.Namespace.Name).Create(context.TODO(), vaultIssuer, metav1.CreateOptions{})
Expect(err).To(HaveOccurred())
Expect(err.Error()).To(ContainSubstring(fmt.Sprintf(
"spec.vault.caBundle: Invalid value: %#+v: specified caBundle and caBundleSecretRef cannot be used together",
vault.Details().VaultCA,
"spec.vault.caBundle: Invalid value: \"<snip>\": specified caBundle and caBundleSecretRef cannot be used together",
)))
Expect(err.Error()).To(ContainSubstring("spec.vault.caBundleSecretRef: Invalid value: \"ca-bundle\": specified caBundleSecretRef and caBundle cannot be used together"))
})