package awsiamauth import ( "context" "fmt" "github.com/google/uuid" "github.com/aws/eks-anywhere/pkg/cluster" "github.com/aws/eks-anywhere/pkg/crypto" "github.com/aws/eks-anywhere/pkg/filewriter" "github.com/aws/eks-anywhere/pkg/logger" "github.com/aws/eks-anywhere/pkg/types" ) // KubernetesClient provides Kubernetes API access. type KubernetesClient interface { Apply(ctx context.Context, cluster *types.Cluster, data []byte) error GetAPIServerURL(ctx context.Context, cluster *types.Cluster) (string, error) GetClusterCACert(ctx context.Context, cluster *types.Cluster, clusterName string) ([]byte, error) } // Installer provides the necessary behavior for installing the AWS IAM Authenticator. type Installer struct { certgen crypto.CertificateGenerator templateBuilder *TemplateBuilder clusterID uuid.UUID k8s KubernetesClient writer filewriter.FileWriter } // NewInstaller creates a new installer instance. func NewInstaller( certgen crypto.CertificateGenerator, clusterID uuid.UUID, k8s KubernetesClient, writer filewriter.FileWriter, ) *Installer { return &Installer{ certgen: certgen, templateBuilder: &TemplateBuilder{}, clusterID: clusterID, k8s: k8s, writer: writer, } } // CreateAndInstallAWSIAMAuthCASecret creates a Kubernetes Secret in cluster containing a // self-signed certificate and key for a cluster identified by clusterName. func (i *Installer) CreateAndInstallAWSIAMAuthCASecret(ctx context.Context, managementCluster *types.Cluster, clusterName string) error { secret, err := i.generateCertKeyPairSecret(clusterName) if err != nil { return fmt.Errorf("generating aws-iam-authenticator ca secret: %v", err) } if err = i.k8s.Apply(ctx, managementCluster, secret); err != nil { return fmt.Errorf("applying aws-iam-authenticator ca secret: %v", err) } return nil } // InstallAWSIAMAuth installs AWS IAM Authenticator deployment manifests into the workload cluster. // It writes a Kubeconfig to disk for kubectl access using AWS IAM Authentication. func (i *Installer) InstallAWSIAMAuth( ctx context.Context, management, workload *types.Cluster, spec *cluster.Spec, ) error { manifest, err := i.generateManifest(spec) if err != nil { return fmt.Errorf("generating aws-iam-authenticator manifest: %v", err) } if err = i.k8s.Apply(ctx, workload, manifest); err != nil { return fmt.Errorf("applying aws-iam-authenticator manifest: %v", err) } if err = i.generateKubeconfig(ctx, management, workload, spec); err != nil { return err } return nil } // UpgradeAWSIAMAuth upgrades an AWS IAM Authenticator deployment in cluster. func (i *Installer) UpgradeAWSIAMAuth(ctx context.Context, cluster *types.Cluster, spec *cluster.Spec) error { awsIamAuthManifest, err := i.generateManifestForUpgrade(spec) if err != nil { return fmt.Errorf("generating manifest: %v", err) } err = i.k8s.Apply(ctx, cluster, awsIamAuthManifest) if err != nil { return fmt.Errorf("applying manifest: %v", err) } return nil } func (i *Installer) generateManifest(clusterSpec *cluster.Spec) ([]byte, error) { return i.templateBuilder.GenerateManifest(clusterSpec, i.clusterID) } func (i *Installer) generateManifestForUpgrade(clusterSpec *cluster.Spec) ([]byte, error) { return i.templateBuilder.GenerateManifest(clusterSpec, uuid.Nil) } func (i *Installer) generateCertKeyPairSecret(managementClusterName string) ([]byte, error) { return i.templateBuilder.GenerateCertKeyPairSecret(i.certgen, managementClusterName) } func (i *Installer) generateInstallerKubeconfig(clusterSpec *cluster.Spec, serverURL, tlsCert string) ([]byte, error) { return i.templateBuilder.GenerateKubeconfig(clusterSpec, i.clusterID, serverURL, tlsCert) } func (i *Installer) generateKubeconfig( ctx context.Context, management, workload *types.Cluster, spec *cluster.Spec, ) error { fileName := fmt.Sprintf("%s-aws.kubeconfig", workload.Name) serverURL, err := i.k8s.GetAPIServerURL(ctx, workload) if err != nil { return fmt.Errorf("generating aws-iam-authenticator kubeconfig: %v", err) } tlsCert, err := i.k8s.GetClusterCACert( ctx, management, workload.Name, ) if err != nil { return fmt.Errorf("generating aws-iam-authenticator kubeconfig: %v", err) } awsIamAuthKubeconfigContent, err := i.generateInstallerKubeconfig(spec, serverURL, string(tlsCert)) if err != nil { return fmt.Errorf("generating aws-iam-authenticator kubeconfig: %v", err) } writtenFile, err := i.writer.Write( fileName, awsIamAuthKubeconfigContent, filewriter.PersistentFile, filewriter.Permission0600, ) if err != nil { return fmt.Errorf("writing aws-iam-authenticator kubeconfig to %s: %v", writtenFile, err) } logger.V(3).Info("Generated aws-iam-authenticator kubeconfig", "kubeconfig", writtenFile) return nil }