@@ -608,7 +608,11 @@ func TestValidateKubeConfig(t *testing.T) {
608
608
609
609
func TestValidateKubeconfigsForExternalCA (t * testing.T ) {
610
610
tmpDir := testutil .SetupTempDir (t )
611
- defer os .RemoveAll (tmpDir )
611
+ defer func () {
612
+ if err := os .RemoveAll (tmpDir ); err != nil {
613
+ t .Error (err )
614
+ }
615
+ }()
612
616
pkiDir := filepath .Join (tmpDir , "pki" )
613
617
614
618
initConfig := & kubeadmapi.InitConfiguration {
@@ -623,11 +627,9 @@ func TestValidateKubeconfigsForExternalCA(t *testing.T) {
623
627
624
628
// creates CA, write to pkiDir and remove ca.key to get into external CA condition
625
629
caCert , caKey := certstestutil .SetupCertificateAuthority (t )
626
- if err := pkiutil .WriteCertAndKey (pkiDir , kubeadmconstants .CACertAndKeyBaseName , caCert , caKey ); err != nil {
627
- t .Fatalf ("failure while saving CA certificate and key: %v" , err )
628
- }
629
- if err := os .Remove (filepath .Join (pkiDir , kubeadmconstants .CAKeyName )); err != nil {
630
- t .Fatalf ("failure while deleting ca.key: %v" , err )
630
+
631
+ if err := pkiutil .WriteCertBundle (pkiDir , kubeadmconstants .CACertAndKeyBaseName , []* x509.Certificate {caCert }); err != nil {
632
+ t .Fatalf ("failure while saving CA certificate: %v" , err )
631
633
}
632
634
633
635
notAfter , _ := time .Parse (time .RFC3339 , "2026-01-02T15:04:05Z" )
@@ -697,7 +699,11 @@ func TestValidateKubeconfigsForExternalCA(t *testing.T) {
697
699
for name , test := range tests {
698
700
t .Run (name , func (t * testing.T ) {
699
701
tmpdir := testutil .SetupTempDir (t )
700
- defer os .RemoveAll (tmpdir )
702
+ defer func () {
703
+ if err := os .RemoveAll (tmpdir ); err != nil {
704
+ t .Error (err )
705
+ }
706
+ }()
701
707
702
708
for name , config := range test .filesToWrite {
703
709
if err := createKubeConfigFileIfNotExists (tmpdir , name , config ); err != nil {
@@ -719,6 +725,166 @@ func TestValidateKubeconfigsForExternalCA(t *testing.T) {
719
725
}
720
726
}
721
727
728
+ func TestValidateKubeconfigsForExternalCAMissingRoot (t * testing.T ) {
729
+ tmpDir := testutil .SetupTempDir (t )
730
+ defer func () {
731
+ if err := os .RemoveAll (tmpDir ); err != nil {
732
+ t .Error (err )
733
+ }
734
+ }()
735
+ pkiDir := filepath .Join (tmpDir , "pki" )
736
+
737
+ initConfig := & kubeadmapi.InitConfiguration {
738
+ ClusterConfiguration : kubeadmapi.ClusterConfiguration {
739
+ CertificatesDir : pkiDir ,
740
+ },
741
+ LocalAPIEndpoint : kubeadmapi.APIEndpoint {
742
+ BindPort : 1234 ,
743
+ AdvertiseAddress : "1.2.3.4" ,
744
+ },
745
+ }
746
+
747
+ // Creates CA, write to pkiDir and remove ca.key to get into external CA mode
748
+ caCert , caKey := certstestutil .SetupCertificateAuthority (t )
749
+
750
+ // Setup multiple intermediate certificate authorities (CAs) for testing purposes.
751
+ // This is "Root CA" signs "Intermediate Authority 1A" signs "Intermediate Authority 2A"
752
+ intermediateCACert1a , intermediateCAKey1a := certstestutil .SetupIntermediateCertificateAuthority (t , caCert , caKey , "Intermediate Authority 1A" )
753
+ intermediateCACert2a , intermediateCAKey2a := certstestutil .SetupIntermediateCertificateAuthority (t , intermediateCACert1a , intermediateCAKey1a , "Intermediate Authority 1A" )
754
+
755
+ // These two CA certificates should both validate using the Intermediate CA 2B certificate
756
+ // This is "Root CA" signs "Intermediate Authority 1B" signs "Intermediate Authority 2B"
757
+ intermediateCACert1b , intermediateCAKey1b := certstestutil .SetupIntermediateCertificateAuthority (t , caCert , caKey , "Intermediate Authority 1B" )
758
+ intermediateCACert2b , intermediateCAKey2b := certstestutil .SetupIntermediateCertificateAuthority (t , intermediateCACert1b , intermediateCAKey1b , "Intermediate Authority 2B" )
759
+
760
+ notAfter , _ := time .Parse (time .RFC3339 , "2036-01-02T15:04:05Z" )
761
+ clusterName := "myOrg1"
762
+
763
+ var validCaCertBundle []* x509.Certificate
764
+ validCaCertBundle = append (validCaCertBundle , caCert , intermediateCACert1a , intermediateCACert2a )
765
+ multipleCAConfigRootCAIssuer := setupKubeConfigWithClientAuth (t , caCert , caKey , notAfter , "https://1.2.3.4:1234" , "test-cluster" , clusterName )
766
+ multipleCAConfigIntermediateCA1aIssuer := setupKubeConfigWithClientAuth (t , intermediateCACert1a , intermediateCAKey1a , notAfter , "https://1.2.3.4:1234" , "test-cluster" , clusterName )
767
+ multipleCAConfigIntermediateCA2aIssuer := setupKubeConfigWithClientAuth (t , intermediateCACert2a , intermediateCAKey2a , notAfter , "https://1.2.3.4:1234" , "test-cluster" , clusterName )
768
+
769
+ var caBundleMissingRootCA []* x509.Certificate
770
+ caBundleMissingRootCA = append (caBundleMissingRootCA , intermediateCACert1b , intermediateCACert2b )
771
+ multipleCAConfigNoRootCA := setupKubeConfigWithClientAuth (t , intermediateCACert2b , intermediateCAKey2b , notAfter , "https://1.2.3.4:1234" , "test-cluster" , clusterName )
772
+ multipleCAConfigDifferentIssuer := setupKubeConfigWithClientAuth (t , intermediateCACert2a , intermediateCAKey2a , notAfter , "https://1.2.3.4:1234" , "test-cluster" , clusterName )
773
+
774
+ var caBundlePartialChain []* x509.Certificate
775
+ caBundlePartialChain = append (caBundlePartialChain , intermediateCACert1a )
776
+ multipleCaPartialCA := setupKubeConfigWithClientAuth (t , intermediateCACert2b , intermediateCAKey2b , notAfter , "https://1.2.3.4:1234" , "test-cluster" , clusterName )
777
+
778
+ tests := map [string ]struct {
779
+ filesToWrite map [string ]* clientcmdapi.Config
780
+ initConfig * kubeadmapi.InitConfiguration
781
+ expectedError bool
782
+ caCertificate []* x509.Certificate
783
+ }{
784
+ // Positive test cases
785
+ "valid config issued from RootCA" : {
786
+ filesToWrite : map [string ]* clientcmdapi.Config {
787
+ kubeadmconstants .AdminKubeConfigFileName : multipleCAConfigRootCAIssuer ,
788
+ kubeadmconstants .SuperAdminKubeConfigFileName : multipleCAConfigRootCAIssuer ,
789
+ kubeadmconstants .KubeletKubeConfigFileName : multipleCAConfigRootCAIssuer ,
790
+ kubeadmconstants .ControllerManagerKubeConfigFileName : multipleCAConfigRootCAIssuer ,
791
+ kubeadmconstants .SchedulerKubeConfigFileName : multipleCAConfigRootCAIssuer ,
792
+ },
793
+ caCertificate : validCaCertBundle ,
794
+ initConfig : initConfig ,
795
+ expectedError : false ,
796
+ },
797
+ "valid config issued from IntermediateCA 1A" : {
798
+ filesToWrite : map [string ]* clientcmdapi.Config {
799
+ kubeadmconstants .AdminKubeConfigFileName : multipleCAConfigIntermediateCA1aIssuer ,
800
+ kubeadmconstants .SuperAdminKubeConfigFileName : multipleCAConfigIntermediateCA1aIssuer ,
801
+ kubeadmconstants .KubeletKubeConfigFileName : multipleCAConfigIntermediateCA1aIssuer ,
802
+ kubeadmconstants .ControllerManagerKubeConfigFileName : multipleCAConfigIntermediateCA1aIssuer ,
803
+ kubeadmconstants .SchedulerKubeConfigFileName : multipleCAConfigIntermediateCA1aIssuer ,
804
+ },
805
+ caCertificate : validCaCertBundle ,
806
+ initConfig : initConfig ,
807
+ expectedError : false ,
808
+ },
809
+ "valid config issued from IntermediateCA 2A" : {
810
+ filesToWrite : map [string ]* clientcmdapi.Config {
811
+ kubeadmconstants .AdminKubeConfigFileName : multipleCAConfigIntermediateCA2aIssuer ,
812
+ kubeadmconstants .SuperAdminKubeConfigFileName : multipleCAConfigIntermediateCA2aIssuer ,
813
+ kubeadmconstants .KubeletKubeConfigFileName : multipleCAConfigIntermediateCA2aIssuer ,
814
+ kubeadmconstants .ControllerManagerKubeConfigFileName : multipleCAConfigIntermediateCA2aIssuer ,
815
+ kubeadmconstants .SchedulerKubeConfigFileName : multipleCAConfigIntermediateCA2aIssuer ,
816
+ },
817
+ caCertificate : validCaCertBundle ,
818
+ initConfig : initConfig ,
819
+ expectedError : false ,
820
+ },
821
+ "valid config issued from IntermediateCA 2B, CA missing root certificate" : {
822
+ filesToWrite : map [string ]* clientcmdapi.Config {
823
+ kubeadmconstants .AdminKubeConfigFileName : multipleCAConfigNoRootCA ,
824
+ kubeadmconstants .SuperAdminKubeConfigFileName : multipleCAConfigNoRootCA ,
825
+ kubeadmconstants .KubeletKubeConfigFileName : multipleCAConfigNoRootCA ,
826
+ kubeadmconstants .ControllerManagerKubeConfigFileName : multipleCAConfigNoRootCA ,
827
+ kubeadmconstants .SchedulerKubeConfigFileName : multipleCAConfigNoRootCA ,
828
+ },
829
+ caCertificate : caBundleMissingRootCA ,
830
+ initConfig : initConfig ,
831
+ expectedError : false ,
832
+ },
833
+ // Negative test cases
834
+ "invalid config issued from IntermediateCA 2A, testing a chain with a different issuer" : {
835
+ filesToWrite : map [string ]* clientcmdapi.Config {
836
+ kubeadmconstants .AdminKubeConfigFileName : multipleCAConfigDifferentIssuer ,
837
+ kubeadmconstants .SuperAdminKubeConfigFileName : multipleCAConfigDifferentIssuer ,
838
+ kubeadmconstants .KubeletKubeConfigFileName : multipleCAConfigDifferentIssuer ,
839
+ kubeadmconstants .ControllerManagerKubeConfigFileName : multipleCAConfigDifferentIssuer ,
840
+ kubeadmconstants .SchedulerKubeConfigFileName : multipleCAConfigDifferentIssuer ,
841
+ },
842
+ caCertificate : caBundleMissingRootCA ,
843
+ initConfig : initConfig ,
844
+ expectedError : true ,
845
+ },
846
+ "invalid config issued from IntermediateCA 2B chain, CA only contains Intermediate 1A" : {
847
+ filesToWrite : map [string ]* clientcmdapi.Config {
848
+ kubeadmconstants .AdminKubeConfigFileName : multipleCaPartialCA ,
849
+ kubeadmconstants .SuperAdminKubeConfigFileName : multipleCaPartialCA ,
850
+ kubeadmconstants .KubeletKubeConfigFileName : multipleCaPartialCA ,
851
+ kubeadmconstants .ControllerManagerKubeConfigFileName : multipleCaPartialCA ,
852
+ kubeadmconstants .SchedulerKubeConfigFileName : multipleCaPartialCA ,
853
+ },
854
+ caCertificate : caBundlePartialChain ,
855
+ initConfig : initConfig ,
856
+ expectedError : true ,
857
+ },
858
+ }
859
+
860
+ for name , test := range tests {
861
+ t .Run (name , func (t * testing.T ) {
862
+ tmpdir := testutil .SetupTempDir (t )
863
+ defer func () {
864
+ if err := os .RemoveAll (tmpdir ); err != nil {
865
+ t .Error (err )
866
+ }
867
+ }()
868
+
869
+ for name , config := range test .filesToWrite {
870
+ if err := createKubeConfigFileIfNotExists (tmpdir , name , config ); err != nil {
871
+ t .Errorf ("createKubeConfigFileIfNotExists failed: %v" , err )
872
+ }
873
+ }
874
+
875
+ if err := pkiutil .WriteCertBundle (pkiDir , kubeadmconstants .CACertAndKeyBaseName , test .caCertificate ); err != nil {
876
+ t .Fatalf ("Failure while saving CA certificate: %v" , err )
877
+ }
878
+
879
+ err := ValidateKubeconfigsForExternalCA (tmpdir , test .initConfig )
880
+ if (err != nil ) != test .expectedError {
881
+ t .Fatalf ("ValidateKubeconfigsForExternalCA failed\n %s\n expected error: %t\n \t got: %t\n error: %v" ,
882
+ name , test .expectedError , (err != nil ), err )
883
+ }
884
+ })
885
+ }
886
+ }
887
+
722
888
// setupKubeConfigWithClientAuth is a test utility function that wraps buildKubeConfigFromSpec for building a KubeConfig object With ClientAuth
723
889
func setupKubeConfigWithClientAuth (t * testing.T , caCert * x509.Certificate , caKey crypto.Signer , notAfter time.Time , apiServer , clientName , clustername string , organizations ... string ) * clientcmdapi.Config {
724
890
spec := & kubeConfigSpec {
@@ -740,7 +906,7 @@ func setupKubeConfigWithClientAuth(t *testing.T, caCert *x509.Certificate, caKey
740
906
return config
741
907
}
742
908
743
- // setupKubeConfigWithClientAuth is a test utility function that wraps buildKubeConfigFromSpec for building a KubeConfig object With Token
909
+ // setupKubeConfigWithTokenAuth is a test utility function that wraps buildKubeConfigFromSpec for building a KubeConfig object With Token
744
910
func setupKubeConfigWithTokenAuth (t * testing.T , caCert * x509.Certificate , apiServer , clientName , token , clustername string ) * clientcmdapi.Config {
745
911
spec := & kubeConfigSpec {
746
912
CACert : caCert ,
0 commit comments