66 "fmt"
77 "io"
88 "os"
9+ "path"
910 "path/filepath"
1011 "strings"
1112 "testing"
@@ -16,6 +17,7 @@ import (
1617 "github.com/linkerd/linkerd2/pkg/tls"
1718 "helm.sh/helm/v3/pkg/cli/values"
1819 corev1 "k8s.io/api/core/v1"
20+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
1921)
2022
2123const (
@@ -314,6 +316,240 @@ func TestRender(t *testing.T) {
314316 }
315317}
316318
319+ // TestOverrideIssuer calls install control plane with the goal of testing
320+ // options overrides for initialize issuer credentials.
321+ func TestOverrideIssuer (t * testing.T ) {
322+ removeIssuerCrt := func () (* charts.Values , error ) {
323+ t .Helper ()
324+ values , err := testInstallOptionsFakeCerts ()
325+ if err != nil {
326+ return nil , err
327+ }
328+ values .Identity .Issuer .TLS .CrtPEM = ""
329+ return values , nil
330+ }
331+ removeIssuerKey := func () (* charts.Values , error ) {
332+ t .Helper ()
333+ values , err := testInstallOptionsFakeCerts ()
334+ if err != nil {
335+ return nil , err
336+ }
337+ values .Identity .Issuer .TLS .KeyPEM = ""
338+ return values , nil
339+ }
340+ removeTrustAnchor := func () (* charts.Values , error ) {
341+ t .Helper ()
342+ values , err := testInstallOptionsFakeCerts ()
343+ if err != nil {
344+ return nil , err
345+ }
346+ values .IdentityTrustAnchorsPEM = ""
347+ return values , nil
348+ }
349+ read := func (filename string ) []byte {
350+ t .Helper ()
351+ data , err := os .ReadFile (path .Join ("testdata" , filename ))
352+ if err != nil {
353+ t .Fatalf ("cannot read filename=%s err=%v" , filename , err )
354+ }
355+ return data
356+ }
357+ // newK8S returns a test implementation of the k8s API; after setting the
358+ // issuer trust anchor and tls crt+key as a secret.
359+ newK8S := func () * k8s.KubernetesAPI {
360+ t .Helper ()
361+ api , err := k8s .NewFakeAPI ()
362+ if err != nil {
363+ t .Fatalf ("cannot create new fake-api from manifests err=%v" , err )
364+ }
365+ _ , err = api .CoreV1 ().Secrets (controlPlaneNamespace ).Create (context .Background (),
366+ & corev1.Secret {
367+ ObjectMeta : metav1.ObjectMeta {
368+ Name : k8s .IdentityIssuerSecretName ,
369+ Namespace : controlPlaneNamespace ,
370+ },
371+ Data : map [string ][]byte {
372+ k8s .IdentityIssuerTrustAnchorsNameExternal : read ("valid-trust-anchors.pem" ),
373+ corev1 .TLSCertKey : read ("valid-crt.pem" ),
374+ corev1 .TLSPrivateKeyKey : read ("valid-key.pem" ),
375+ }}, metav1.CreateOptions {})
376+ if err != nil {
377+ t .Fatalf ("cannot create secret for new-k8s-api err=%v" , err )
378+ }
379+ return api
380+ }
381+ controlPlaneNamespace = defaultLinkerdNamespace
382+ for i , test := range []struct {
383+ options values.Options
384+ values func () (* charts.Values , error )
385+ k8sAPI * k8s.KubernetesAPI
386+ expErr string
387+ expIdentityTrustAnchor bool
388+ expIssuerCrt bool
389+ expIssuerKey bool
390+ expIssuerName string
391+ }{
392+ {
393+ // no options; no certs in values -> generated anchor; key + crt
394+ options : values.Options {},
395+ values : testInstallValuesNoCertsNoHA ,
396+ k8sAPI : nil ,
397+ expIdentityTrustAnchor : true ,
398+ expIssuerKey : true ,
399+ expIssuerCrt : true ,
400+ expIssuerName : fmt .Sprintf ("identity.%s.%s" ,
401+ controlPlaneNamespace , "test-override-issuer" ),
402+ },
403+ {
404+ // no options; fake certs in values -> fake certs untouched
405+ options : values.Options {},
406+ values : testInstallOptionsFakeCerts ,
407+ k8sAPI : nil ,
408+ expIdentityTrustAnchor : true ,
409+ expIssuerKey : true ,
410+ expIssuerCrt : true ,
411+ expIssuerName : "identity.linkerd.cluster.local" ,
412+ },
413+ {
414+ // issuer scheme in options; no certs in values; nil k8s api ->
415+ // error trying to call k8s
416+ options : values.Options {
417+ Values : []string {"identity.issuer.scheme=kubernetes.io/tls" },
418+ },
419+ values : testInstallValuesNoCertsNoHA ,
420+ k8sAPI : nil ,
421+ expErr : "--ignore-cluster is not supported when --identity-external-issuer=true" ,
422+ expIdentityTrustAnchor : false ,
423+ expIssuerKey : false ,
424+ expIssuerCrt : false ,
425+ expIssuerName : "" ,
426+ },
427+ {
428+ // issuer scheme in options; no certs in values; fake k8s api ->
429+ // trust anchor is set
430+ options : values.Options {
431+ Values : []string {"identity.issuer.scheme=kubernetes.io/tls" },
432+ },
433+ values : testInstallValuesNoCertsNoHA ,
434+ k8sAPI : newK8S (),
435+ expErr : "" ,
436+ expIdentityTrustAnchor : true ,
437+ expIssuerKey : false ,
438+ expIssuerCrt : false ,
439+ expIssuerName : "identity.linkerd.cluster.local" ,
440+ },
441+ {
442+ // no options; fake certs in values; remove trust anchor -> err
443+ options : values.Options {},
444+ values : removeTrustAnchor ,
445+ k8sAPI : nil ,
446+ expErr : "a trust anchors file must be specified if other credentials are provided" ,
447+ expIdentityTrustAnchor : false ,
448+ expIssuerCrt : true ,
449+ expIssuerKey : true ,
450+ expIssuerName : "identity.linkerd.cluster.local" ,
451+ },
452+ {
453+ // no options; fake certs in values; remove issuer crt -> err
454+ options : values.Options {},
455+ values : removeIssuerCrt ,
456+ k8sAPI : nil ,
457+ expErr : "a certificate file must be specified if other credentials are provided" ,
458+ expIdentityTrustAnchor : true ,
459+ expIssuerCrt : false ,
460+ expIssuerName : "identity.linkerd.cluster.local" ,
461+ expIssuerKey : true ,
462+ },
463+ {
464+ // no options; fake certs in values; remove issuer key -> err
465+ options : values.Options {},
466+ values : removeIssuerKey ,
467+ k8sAPI : nil ,
468+ expErr : "a private key file must be specified if other credentials are provided" ,
469+ expIdentityTrustAnchor : true ,
470+ expIssuerCrt : true ,
471+ expIssuerName : "identity.linkerd.cluster.local" ,
472+ expIssuerKey : false ,
473+ },
474+ } {
475+ values , err := test .values ()
476+ if err != nil {
477+ t .Fatalf ("%02d/test install options failed with an error err=%v" , i , err )
478+ }
479+ values .IdentityTrustDomain = "test-override-issuer"
480+ // ensure the install options created above meet expectations (we are
481+ // testing the override not the values)
482+ if values .Identity .Issuer .Scheme != k8s .IdentityIssuerSchemeLinkerd {
483+ t .Fatalf ("%02d/identity issuer scheme is incorrect: %s != %s" , i ,
484+ k8s .IdentityIssuerSchemeLinkerd , values .Identity .Issuer .Scheme )
485+ }
486+ var buf bytes.Buffer
487+ err = installControlPlane (context .Background (), test .k8sAPI , & buf , values , nil , test .options , "yaml" )
488+ if test .expErr != "" {
489+ if test .expErr != err .Error () {
490+ t .Fatalf ("%02d/install control plane returned incorrect error %s<>%v" , i , test .expErr , err )
491+ }
492+ } else {
493+ if err != nil {
494+ t .Fatalf ("%02d/install control plane failed with an error=%v" , i , err )
495+ }
496+ }
497+ if test .expIdentityTrustAnchor {
498+ if values .IdentityTrustAnchorsPEM == "" {
499+ t .Fatalf ("%02d/identity trust-anchors-pem is empty" , i )
500+ }
501+ crt , err := tls .DecodePEMCrt (values .IdentityTrustAnchorsPEM )
502+ if err != nil {
503+ t .Fatalf ("%02d/generated identity-trust-anchors-pem cannot be decoded" , i )
504+ }
505+ if crt == nil {
506+ t .Fatalf ("%02d/generated identity-trust-anchors-pem cannot be decoded (nil)" , i )
507+ }
508+ if crt .Certificate == nil {
509+ t .Fatalf ("%02d/generated identity-trust-anchors-pem certificate is invalid" , i )
510+ }
511+ if test .expIssuerName != crt .Certificate .Issuer .CommonName {
512+ t .Fatalf ("%02d/generated identity-trust-anchors-pem certificate common-name is incorrect %s<>%s" , i ,
513+ test .expIssuerName ,
514+ crt .Certificate .Issuer .CommonName )
515+ }
516+ } else if values .IdentityTrustAnchorsPEM != "" {
517+ t .Fatalf ("%02d/identity was incorrectly set pem=%s" , i , values .IdentityTrustAnchorsPEM )
518+ }
519+ if test .expIssuerCrt {
520+ if values .Identity .Issuer .TLS .CrtPEM == "" {
521+ t .Fatalf ("%02d/generated identity-issuer-tls-crt-pem is empty" , i )
522+ }
523+ crt , err := tls .DecodePEMCrt (values .Identity .Issuer .TLS .CrtPEM )
524+ if err != nil {
525+ t .Fatalf ("%02d/generated identity-issuer-tls-crt-pem cannot be decoded err=%v" , i , err )
526+ }
527+ if crt == nil {
528+ t .Fatalf ("%02d/generated identity-issuer-tls-crt-pem cannot be decoded (nil)" , i )
529+ }
530+ if crt .Certificate == nil {
531+ t .Fatalf ("%02d/generated identity-issuer-tls-crt-pem certificate is invalid (nil)" , i )
532+ }
533+ } else if values .Identity .Issuer .TLS .CrtPEM != "" {
534+ t .Fatalf ("%02d/identity issuer crt was incorrectly set pem=%s" , i , values .Identity .Issuer .TLS .CrtPEM )
535+ }
536+ if test .expIssuerKey {
537+ if values .Identity .Issuer .TLS .KeyPEM == "" {
538+ t .Fatalf ("%02d/generated identity-issuer-tls-key-pem is empty" , i )
539+ }
540+ key , err := tls .DecodePEMKey (values .Identity .Issuer .TLS .KeyPEM )
541+ if err != nil {
542+ t .Fatalf ("%02d/generated identity-issuer-tls-key-pem cannot be decoded err=%v" , i , err )
543+ }
544+ if key == nil {
545+ t .Fatalf ("%02d/generated identity-issuer-tls-key-pem cannot be decoded (nil)" , i )
546+ }
547+ } else if values .Identity .Issuer .TLS .KeyPEM != "" {
548+ t .Fatalf ("%02d/identity issuer tls key was incorrectly set pem=%s" , i , values .Identity .Issuer .TLS .KeyPEM )
549+ }
550+ }
551+ }
552+
317553func TestIgnoreCluster (t * testing.T ) {
318554 defaultValues , err := testInstallOptions ()
319555 if err != nil {
@@ -550,6 +786,10 @@ func testInstallOptionsNoCerts(ha bool) (*charts.Values, error) {
550786 return values , nil
551787}
552788
789+ func testInstallValuesNoCertsNoHA () (* charts.Values , error ) {
790+ return testInstallOptionsNoCerts (false )
791+ }
792+
553793func testInstallValues () (* charts.Values , error ) {
554794 values , err := charts .NewValues ()
555795 if err != nil {
0 commit comments