diff --git a/pkg/cmd/init/cmd.go b/pkg/cmd/init/cmd.go index a421b5b1..a80d0231 100644 --- a/pkg/cmd/init/cmd.go +++ b/pkg/cmd/init/cmd.go @@ -85,6 +85,10 @@ func NewCmd(clusteradmFlags *genericclioptionsclusteradm.ClusteradmFlags, stream "The type of authentication to use for registering and authenticating with hub. Only csr and awsirsa are accepted as valid inputs. This flag can be repeated to specify multiple authentication types.") cmd.Flags().StringVar(&o.hubClusterArn, "hub-cluster-arn", "", "The hubCluster ARN to be passed if awsirsa is one of the registrationAuths and the cluster name in EKS kubeconfig doesn't contain hubClusterArn") - + + cmd.Flags().StringArrayVar(&o.csrIdentities, "auto-approved-csr-identity", []string{}, + "The user or identity that can be auto approve for CSR and auto accepted to join with hub cluster") + cmd.Flags().StringArrayVar(&o.awsIdentityPatterns, "auto-approved-aws-identity-pattern", []string{}, + "A pattern of AWS EKS ARN so any EKS clusters with this pattern will be auto accepted to join with hub cluster") return cmd } diff --git a/pkg/cmd/init/exec.go b/pkg/cmd/init/exec.go index 94c96341..9affd5db 100644 --- a/pkg/cmd/init/exec.go +++ b/pkg/cmd/init/exec.go @@ -4,10 +4,12 @@ package init import ( "context" "fmt" - "k8s.io/apimachinery/pkg/util/sets" "os" + "slices" "time" + "k8s.io/apimachinery/pkg/util/sets" + "github.com/spf13/cobra" "github.com/spf13/pflag" corev1 "k8s.io/api/core/v1" @@ -75,6 +77,7 @@ func (o *Options) complete(cmd *cobra.Command, args []string) (err error) { if err != nil { return err } + o.clusterManagerChartConfig.ClusterManager = chart.ClusterManagerConfig{ RegistrationConfiguration: operatorv1.RegistrationHubConfiguration{ FeatureGates: genericclioptionsclusteradm.ConvertToFeatureGateAPI( @@ -157,6 +160,31 @@ func (o *Options) validate() error { } } + featureGates := o.clusterManagerChartConfig.ClusterManager.RegistrationConfiguration.FeatureGates + managedClusterAutoApprove := false + + for _, feature := range featureGates { + if feature.Feature == "featuregate/ManagedClusterAutoApproval" { + if feature.Mode == "Enabled" { + managedClusterAutoApprove = true + } + } + } + + if managedClusterAutoApprove { + // If hub registration does not accept awsirsa, we stop user if they also pass in a list of patterns for AWS EKS ARN. + if len(o.awsIdentityPatterns) > 0 && !slices.Contains(o.registrationAuth, "awsirsa") { + return fmt.Errorf("should not provide list of patterns for aws eks arn if not initializing hub with awsirsa registration") + } + + // If hub registration does not accept csr, we stop user if they also pass in a list of users for CSR auto approval. + if len(o.csrIdentities) > 0 && !slices.Contains(o.registrationAuth, "csr") { + return fmt.Errorf("should not provide list of users for csr to auto approve if not initializing hub with csr registration") + } + } else if len(o.awsIdentityPatterns) > 0 || len(o.csrIdentities) > 0 { + return fmt.Errorf("should enable feature gate ManagedClusterAutoApproval before passing list of identities") + } + // If --wait is set, some information during initialize process will print to output, the output would not keep // machine readable, so this behavior should be disabled if o.wait && o.output != "text" { @@ -373,17 +401,16 @@ func getRegistrationDrivers(o *Options) ([]operatorv1.RegistrationDriverHub, err for _, driver := range o.registrationAuth { if driver == "csr" { - registrationDriver = operatorv1.RegistrationDriverHub{AuthType: driver} + registrationDriver = operatorv1.RegistrationDriverHub{AuthType: driver, AutoApprovedIdentities: o.csrIdentities} } else if driver == "awsirsa" { hubClusterArn, err := getHubClusterArn(o) if err != nil { return registrationDrivers, err } - registrationDriver = operatorv1.RegistrationDriverHub{AuthType: driver, HubClusterArn: hubClusterArn} + registrationDriver = operatorv1.RegistrationDriverHub{AuthType: driver, HubClusterArn: hubClusterArn, AutoApprovedIdentities: o.awsIdentityPatterns} } registrationDrivers = append(registrationDrivers, registrationDriver) } - return registrationDrivers, nil } diff --git a/pkg/cmd/init/options.go b/pkg/cmd/init/options.go index 99c99a08..3cc1c747 100644 --- a/pkg/cmd/init/options.go +++ b/pkg/cmd/init/options.go @@ -56,6 +56,11 @@ type Options struct { // The optional ARN to pass if awsirsa is one of the registrationAuths // and the cluster name in EKS kubeconfig doesn't contain hubClusterArn hubClusterArn string + + // A list of users that can be auto approve csr and auto accept to join hub cluster + csrIdentities []string + // A list of AWS EKS ARN patterns that are accepted and whatever matches can be auto accepted to join hub cluster + awsIdentityPatterns []string } func newOptions(clusteradmFlags *genericclioptionsclusteradm.ClusteradmFlags, streams genericiooptions.IOStreams) *Options { diff --git a/test/e2e/clusteradm/init_test.go b/test/e2e/clusteradm/init_test.go index d1630664..97056186 100644 --- a/test/e2e/clusteradm/init_test.go +++ b/test/e2e/clusteradm/init_test.go @@ -69,6 +69,24 @@ var _ = ginkgo.Describe("test clusteradm with bootstrap token in singleton mode" //gomega.Expect(cm.Spec.RegistrationConfiguration.RegistrationDrivers[1].HubClusterArn). // Should(gomega.Equal("arn:aws:eks:us-west-2:123456789012:cluster/hub-cluster1")) + err = e2e.Clusteradm().Init( + "--use-bootstrap-token", + "--context", e2e.Cluster().Hub().Context(), + "--bundle-version=latest", + "--registration-auth awsirsa", + "--registration-auth csr", + "--auto-approved-csr-identity csr1", + "--auto-approved-aws-identity-pattern arn:aws:eks:us-west-2:123456789012:cluster/*", + ) + gomega.Expect(err).NotTo(gomega.HaveOccurred(), "clusteradm init error") + cm, err = operatorClient.OperatorV1().ClusterManagers().Get(context.TODO(), "cluster-manager", metav1.GetOptions{}) + gomega.Expect(err).NotTo(gomega.HaveOccurred()) + // Ensure that the auto approval identities contain user for CSR and pattern for AWS + gomega.Expect(cm.Spec.RegistrationConfiguration.RegistrationDrivers[0].AuthType).Should(gomega.Equal("csr")) + gomega.Expect(cm.Spec.RegistrationConfiguration.RegistrationDrivers[1].AuthType).Should(gomega.Equal("awsirsa")) + gomega.Expect(cm.Spec.RegistrationConfiguration.RegistrationDrivers[0].Identities[0]).Should(gomega.Equal("csr1")) + gomega.Expect(cm.Spec.RegistrationConfiguration.RegistrationDrivers[1].Identities[0]).Should(gomega.Equal("arn:aws:eks:us-west-2:123456789012:cluster/*")) + err = e2e.Clusteradm().Init( "--use-bootstrap-token", "--context", e2e.Cluster().Hub().Context(),