Skip to content

Commit

Permalink
Merge pull request #228 from nzbr/128-subject
Browse files Browse the repository at this point in the history
Add attribute support for certificate subject
  • Loading branch information
cert-manager-prow[bot] authored May 14, 2024
2 parents 6d40aba + 41fcd83 commit c1dbae3
Show file tree
Hide file tree
Showing 4 changed files with 117 additions and 17 deletions.
12 changes: 11 additions & 1 deletion pkg/apis/v1alpha1/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,17 @@ const (
IssuerKindKey = "csi.cert-manager.io/issuer-kind"
IssuerGroupKey = "csi.cert-manager.io/issuer-group"

CommonNameKey = "csi.cert-manager.io/common-name"
LiteralSubjectKey = "csi.cert-manager.io/literal-subject"
CommonNameKey = "csi.cert-manager.io/common-name"
OrganizationsKey = "csi.cert-manager.io/organizations"
OrganizationalUnitsKey = "csi.cert-manager.io/organizationalunits"
CountriesKey = "csi.cert-manager.io/countries"
ProvincesKey = "csi.cert-manager.io/provinces"
LocalitiesKey = "csi.cert-manager.io/localities"
StreetAddressesKey = "csi.cert-manager.io/streetaddresses"
PostalCodesKey = "csi.cert-manager.io/postalcodes"
SerialNumberKey = "csi.cert-manager.io/serialnumber"

DNSNamesKey = "csi.cert-manager.io/dns-names"
IPSANsKey = "csi.cert-manager.io/ip-sans"
URISANsKey = "csi.cert-manager.io/uri-sans"
Expand Down
14 changes: 14 additions & 0 deletions pkg/apis/validation/validation_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ import (
)

func Test_ValidateAttributes(t *testing.T) {
var literalSubject = "CN=${POD_NAME}.${POD_NAMESPACE}.svc.cluster.local,OU=0:${POD_NAME}\\;1:${POD_NAMESPACE}\\;2:my-region\\;4:unittest,O=foo.bar.com"

tests := map[string]struct {
attr map[string]string
expErr field.ErrorList
Expand Down Expand Up @@ -201,6 +203,18 @@ func Test_ValidateAttributes(t *testing.T) {
field.Invalid(field.NewPath("volumeAttributes", "csi.cert-manager.io/privatekey-file"), "/foobar", "filename must not include '/'"),
},
},
"correct literal-subject should not error": {
attr: map[string]string{
csiapi.IssuerNameKey: "test-issuer",
csiapi.LiteralSubjectKey: literalSubject,
csiapi.CAFileKey: "ca.crt",
csiapi.CertFileKey: "crt.tls",
csiapi.KeyFileKey: "key.tls",
csiapi.DNSNamesKey: "foo.bar.com",
csiapi.KeyEncodingKey: "PKCS8",
},
expErr: nil,
},
}

for name, test := range tests {
Expand Down
67 changes: 51 additions & 16 deletions pkg/requestgen/generator.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ import (

cmapi "github.com/cert-manager/cert-manager/pkg/apis/certmanager/v1"
cmmeta "github.com/cert-manager/cert-manager/pkg/apis/meta/v1"
cmutil "github.com/cert-manager/cert-manager/pkg/util"
cmpki "github.com/cert-manager/cert-manager/pkg/util/pki"
"github.com/cert-manager/csi-lib/manager"
"github.com/cert-manager/csi-lib/metadata"

Expand Down Expand Up @@ -57,21 +59,61 @@ func RequestForMetadata(meta metadata.Metadata) (*manager.CertificateRequestBund
}
}

commonName, err := expand(meta, attrs[csiapi.CommonNameKey])
if err != nil {
return nil, fmt.Errorf("%q: %w", csiapi.CommonNameKey, err)
var request = &x509.CertificateRequest{}
if lSubjStr, ok := attrs[csiapi.LiteralSubjectKey]; ok && len(lSubjStr) > 0 {
lSubjStr, err = expand(meta, lSubjStr)
if err != nil {
return nil, fmt.Errorf("%q: %w", csiapi.LiteralSubjectKey, err)
}
rdnSequence, err := cmpki.UnmarshalSubjectStringToRDNSequence(lSubjStr)
if err != nil {
return nil, fmt.Errorf("%q: %w", csiapi.LiteralSubjectKey, err)
}
request.RawSubject, err = cmpki.MarshalRDNSequenceToRawDERBytes(rdnSequence)
if err != nil {
return nil, fmt.Errorf("%q: %w", csiapi.LiteralSubjectKey, err)
}
} else {
request.Subject = pkix.Name{}
request.Subject.CommonName, err = expand(meta, attrs[csiapi.CommonNameKey])
if err != nil {
return nil, fmt.Errorf("%q: %w", csiapi.CommonNameKey, err)
}
if len(attrs[csiapi.SerialNumberKey]) > 0 {
request.Subject.SerialNumber = attrs[csiapi.SerialNumberKey]
}
for k, v := range map[*[]string]string{
&request.Subject.Organization: csiapi.OrganizationsKey,
&request.Subject.OrganizationalUnit: csiapi.OrganizationalUnitsKey,
&request.Subject.Country: csiapi.CountriesKey,
&request.Subject.Province: csiapi.ProvincesKey,
&request.Subject.Locality: csiapi.LocalitiesKey,
&request.Subject.StreetAddress: csiapi.StreetAddressesKey,
&request.Subject.PostalCode: csiapi.PostalCodesKey,
} {
if len(attrs[v]) > 0 {
var e, err = expand(meta, attrs[v])
if err != nil {
return nil, fmt.Errorf("%q: %w", v, err)
}
*k, err = cmutil.SplitWithEscapeCSV(e)
if err != nil {
return nil, fmt.Errorf("%q: %w", v, err)
}
}
}
}
dns, err := parseDNSNames(meta, attrs[csiapi.DNSNamesKey])
request.DNSNames, err = parseDNSNames(meta, attrs[csiapi.DNSNamesKey])
if err != nil {
return nil, fmt.Errorf("%q: %w", csiapi.DNSNamesKey, err)
}
uris, err := parseURIs(meta, attrs[csiapi.URISANsKey])
request.IPAddresses, err = parseIPAddresses(attrs[csiapi.IPSANsKey])
if err != nil {
return nil, fmt.Errorf("%q: %w", csiapi.URISANsKey, err)
return nil, fmt.Errorf("%q: %w", csiapi.IPSANsKey, err)
}
ips, err := parseIPAddresses(attrs[csiapi.IPSANsKey])
request.URIs, err = parseURIs(meta, attrs[csiapi.URISANsKey])
if err != nil {
return nil, fmt.Errorf("%q: %w", csiapi.IPSANsKey, err)
return nil, fmt.Errorf("%q: %w", csiapi.URISANsKey, err)
}

annotations := make(map[string]string)
Expand All @@ -88,14 +130,7 @@ func RequestForMetadata(meta metadata.Metadata) (*manager.CertificateRequestBund
}

return &manager.CertificateRequestBundle{
Request: &x509.CertificateRequest{
Subject: pkix.Name{
CommonName: commonName,
},
DNSNames: dns,
IPAddresses: ips,
URIs: uris,
},
Request: request,
IsCA: strings.ToLower(attrs[csiapi.IsCAKey]) == "true",
Namespace: attrs[csiapi.K8sVolumeContextKeyPodNamespace],
Duration: duration,
Expand Down
41 changes: 41 additions & 0 deletions pkg/requestgen/generator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,18 @@ import (
"errors"
"net"
"net/url"
"strings"
"testing"
"time"

cmapi "github.com/cert-manager/cert-manager/pkg/apis/certmanager/v1"
cmmeta "github.com/cert-manager/cert-manager/pkg/apis/meta/v1"
cmpki "github.com/cert-manager/cert-manager/pkg/util/pki"
"github.com/cert-manager/csi-lib/manager"
"github.com/cert-manager/csi-lib/metadata"
"github.com/stretchr/testify/assert"

csiapi "github.com/cert-manager/csi-driver/pkg/apis/v1alpha1"
)

func Test_RequestForMetadata(t *testing.T) {
Expand All @@ -51,6 +55,17 @@ func Test_RequestForMetadata(t *testing.T) {
return puri
}

var literalSubject = "CN=my-pod.my-namespace.svc.cluster.local,OU=0:my-pod\\;1:my-namespace\\;2:my-region\\;4:unittest,O=foo.bar.com"
rdnSequence, err := cmpki.UnmarshalSubjectStringToRDNSequence(literalSubject)
if err != nil {
assert.NoError(t, err)
}

rawLiteralSubject, err := cmpki.MarshalRDNSequenceToRawDERBytes(rdnSequence)
if err != nil {
assert.NoError(t, err)
}

tests := map[string]struct {
meta metadata.Metadata
expRequest *manager.CertificateRequestBundle
Expand Down Expand Up @@ -175,6 +190,32 @@ func Test_RequestForMetadata(t *testing.T) {
},
expErr: false,
},
"a metadata with literal subject set should be returned": {
meta: baseMetadataWith(metadata.Metadata{VolumeContext: map[string]string{
csiapi.IssuerNameKey: "my-issuer",
csiapi.LiteralSubjectKey: literalSubject,
}}),
expRequest: &manager.CertificateRequestBundle{
Request: &x509.CertificateRequest{RawSubject: rawLiteralSubject},
Usages: cmapi.DefaultKeyUsages(),
Namespace: "my-namespace",
IssuerRef: cmmeta.ObjectReference{
Name: "my-issuer",
Kind: "Issuer",
Group: "cert-manager.io",
},
Duration: cmapi.DefaultCertificateDuration,
Annotations: make(map[string]string),
},
expErr: false,
},
"a metadata with incorrect literal subject set should error": {
meta: baseMetadataWith(metadata.Metadata{VolumeContext: map[string]string{
csiapi.IssuerNameKey: "my-issuer",
csiapi.LiteralSubjectKey: strings.ReplaceAll(literalSubject, ";", "&"),
}}),
expErr: true,
},
}

for name, test := range tests {
Expand Down

0 comments on commit c1dbae3

Please sign in to comment.