diff --git a/cmd/aws/command.go b/cmd/aws/command.go index bd62cede7..43ccf6cdd 100644 --- a/cmd/aws/command.go +++ b/cmd/aws/command.go @@ -19,6 +19,7 @@ var ( cloudRegionFlag string clusterNameFlag string clusterTypeFlag string + dnsProviderFlag string githubOrgFlag string gitlabGroupFlag string gitProviderFlag string @@ -34,10 +35,9 @@ var ( copyKbotPasswordToClipboardFlag bool copyVaultPasswordToClipboardFlag bool - // Supported git providers - supportedGitProviders = []string{"github", "gitlab"} - - // Supported git providers + // Supported argument arrays + supportedDNSProviders = []string{"aws", "cloudflare"} + supportedGitProviders = []string{"github", "gitlab"} supportedGitProtocolOverride = []string{"https", "ssh"} ) @@ -69,7 +69,8 @@ func Create() *cobra.Command { createCmd.Flags().StringVar(&cloudRegionFlag, "cloud-region", "us-east-1", "the aws region to provision infrastructure in") createCmd.Flags().StringVar(&clusterNameFlag, "cluster-name", "kubefirst", "the name of the cluster to create") createCmd.Flags().StringVar(&clusterTypeFlag, "cluster-type", "mgmt", "the type of cluster to create (i.e. mgmt|workload)") - createCmd.Flags().StringVar(&domainNameFlag, "domain-name", "", "the Route53 hosted zone name to use for DNS records (i.e. your-domain.com|subdomain.your-domain.com) (required)") + createCmd.Flags().StringVar(&dnsProviderFlag, "dns-provider", "aws", fmt.Sprintf("the dns provider - one of: %s", supportedDNSProviders)) + createCmd.Flags().StringVar(&domainNameFlag, "domain-name", "", "the Route53/Cloudflare hosted zone name to use for DNS records (i.e. your-domain.com|subdomain.your-domain.com) (required)") createCmd.MarkFlagRequired("domain-name") createCmd.Flags().StringVar(&gitProviderFlag, "git-provider", "github", fmt.Sprintf("the git provider - one of: %s", supportedGitProviders)) createCmd.Flags().StringVar(&gitProtocolFlag, "git-protocol", "ssh", fmt.Sprintf("the git protocol - one of: %s", supportedGitProtocolOverride)) diff --git a/cmd/aws/create.go b/cmd/aws/create.go index a0433cb9c..df1f45882 100644 --- a/cmd/aws/create.go +++ b/cmd/aws/create.go @@ -31,7 +31,6 @@ import ( "github.com/kubefirst/runtime/pkg" "github.com/kubefirst/runtime/pkg/argocd" awsinternal "github.com/kubefirst/runtime/pkg/aws" - "github.com/kubefirst/runtime/pkg/bootstrap" "github.com/kubefirst/runtime/pkg/dns" "github.com/kubefirst/runtime/pkg/gitClient" "github.com/kubefirst/runtime/pkg/github" @@ -85,10 +84,10 @@ func createAws(cmd *cobra.Command, args []string) error { return err } - // dnsProviderFlag, err := cmd.Flags().GetString("dns-provider") - // if err != nil { - // return err - // } + dnsProviderFlag, err := cmd.Flags().GetString("dns-provider") + if err != nil { + return err + } domainNameFlag, err := cmd.Flags().GetString("domain-name") if err != nil { @@ -180,7 +179,7 @@ func createAws(cmd *cobra.Command, args []string) error { // required for destroy command viper.Set("flags.alerts-email", alertsEmailFlag) viper.Set("flags.cluster-name", clusterNameFlag) - // viper.Set("flags.dns-provider", dnsProviderFlag) + viper.Set("flags.dns-provider", dnsProviderFlag) viper.Set("flags.domain-name", domainNameFlag) viper.Set("flags.git-provider", gitProviderFlag) viper.Set("flags.git-protocol", gitProtocolFlag) @@ -279,7 +278,14 @@ func createAws(cmd *cobra.Command, args []string) error { } // Instantiate config - config := providerConfigs.GetConfig(clusterNameFlag, domainNameFlag, gitProviderFlag, cGitOwner, gitProtocolFlag) + config := providerConfigs.GetConfig( + clusterNameFlag, + domainNameFlag, + gitProviderFlag, + cGitOwner, + gitProtocolFlag, + os.Getenv("CF_API_TOKEN"), + ) customTransport := http.DefaultTransport.(*http.Transport).Clone() customTransport.TLSClientConfig = &tls.Config{InsecureSkipVerify: true} @@ -375,6 +381,13 @@ func createAws(cmd *cobra.Command, args []string) error { } } + // Validate required environment variables for dns provider + if dnsProviderFlag == "cloudflare" { + if os.Getenv("CF_API_TOKEN") == "" { + return fmt.Errorf("your CF_API_TOKEN environment variable is not set. Please set and try again") + } + } + log.Info().Msgf("kubefirst version configs.K1Version: %s ", configs.K1Version) log.Info().Msgf("cloning gitops-template repo url: %s ", gitopsTemplateURLFlag) log.Info().Msgf("cloning gitops-template repo branch: %s ", gitopsTemplateBranchFlag) @@ -469,45 +482,45 @@ func createAws(cmd *cobra.Command, args []string) error { if !skipDomainCheck { telemetryShim.Transmit(useTelemetryFlag, segmentClient, segment.MetricDomainLivenessStarted, "") - // switch dnsProviderFlag { - // case "aws": - // verify dns - isPrivateZone, nameServers, err := awsClient.GetHostedZoneNameServers(domainNameFlag) - if err != nil { - return err - } - - if !isPrivateZone { - err = dns.VerifyProviderDNS("aws", cloudRegionFlag, domainNameFlag, nameServers) + switch dnsProviderFlag { + case "aws": + //verify dns + isPrivateZone, nameServers, err := awsClient.GetHostedZoneNameServers(domainNameFlag) if err != nil { return err } - } - domainLiveness := awsClient.TestHostedZoneLiveness(domainNameFlag) - if !domainLiveness { - telemetryShim.Transmit(useTelemetryFlag, segmentClient, segment.MetricDomainLivenessFailed, "domain liveness test failed") - msg := "failed to check the liveness of the HostedZone. A valid public HostedZone on the same AWS " + - "account as the one where Kubefirst will be installed is required for this operation to " + - "complete.\nTroubleshoot Steps:\n\n - Make sure you are using the correct AWS account and " + - "region.\n - Verify that you have the necessary permissions to access the hosted zone.\n - Check " + - "that the hosted zone is correctly configured and is a public hosted zone\n - Check if the " + - "hosted zone exists and has the correct name and domain.\n - If you don't have a HostedZone," + - "please follow these instructions to create one: " + - "https://docs.aws.amazon.com/Route53/latest/DeveloperGuide/hosted-zones-working-with.html \n\n" + - "if you are still facing issues please reach out to support team for further assistance" + if !isPrivateZone { + err = dns.VerifyProviderDNS("aws", cloudRegionFlag, domainNameFlag, nameServers) + if err != nil { + return err + } + } - return fmt.Errorf(msg) + domainLiveness := awsClient.TestHostedZoneLiveness(domainNameFlag) + if !domainLiveness { + telemetryShim.Transmit(useTelemetryFlag, segmentClient, segment.MetricDomainLivenessFailed, "domain liveness test failed") + msg := "failed to check the liveness of the HostedZone. A valid public HostedZone on the same AWS " + + "account as the one where Kubefirst will be installed is required for this operation to " + + "complete.\nTroubleshoot Steps:\n\n - Make sure you are using the correct AWS account and " + + "region.\n - Verify that you have the necessary permissions to access the hosted zone.\n - Check " + + "that the hosted zone is correctly configured and is a public hosted zone\n - Check if the " + + "hosted zone exists and has the correct name and domain.\n - If you don't have a HostedZone," + + "please follow these instructions to create one: " + + "https://docs.aws.amazon.com/Route53/latest/DeveloperGuide/hosted-zones-working-with.html \n\n" + + "if you are still facing issues please reach out to support team for further assistance" + + return fmt.Errorf(msg) + } + viper.Set("kubefirst-checks.domain-liveness", true) + viper.WriteConfig() + telemetryShim.Transmit(useTelemetryFlag, segmentClient, segment.MetricDomainLivenessCompleted, "") + progressPrinter.IncrementTracker("preflight-checks", 1) + case "cloudflare": + // Implement a Cloudflare check at some point + log.Info().Msg("domain check already complete - continuing") + progressPrinter.IncrementTracker("preflight-checks", 1) } - viper.Set("kubefirst-checks.domain-liveness", true) - viper.WriteConfig() - telemetryShim.Transmit(useTelemetryFlag, segmentClient, segment.MetricDomainLivenessCompleted, "") - progressPrinter.IncrementTracker("preflight-checks", 1) - // case "cloudflare": - // // Implement a Cloudflare check at some point - // log.Info().Msg("domain check already complete - continuing") - // progressPrinter.IncrementTracker("preflight-checks", 1) - // } } else { log.Info().Msg("domain check already complete - continuing") progressPrinter.IncrementTracker("preflight-checks", 1) @@ -584,17 +597,26 @@ func createAws(cmd *cobra.Command, args []string) error { containerRegistryURL = fmt.Sprintf("%s/%s/metaphor", containerRegistryHost, cGitOwner) } + var externalDNSProviderTokenEnvName, externalDNSProviderSecretKey string + if dnsProviderFlag == "cloudflare" { + externalDNSProviderTokenEnvName = "CF_API_TOKEN" + externalDNSProviderSecretKey = "cf-api-token" + } else { + externalDNSProviderTokenEnvName = "CIVO_TOKEN" + externalDNSProviderSecretKey = fmt.Sprintf("%s-token", awsinternal.CloudProvider) + } + gitopsDirectoryTokens := providerConfigs.GitOpsDirectoryValues{ - AlertsEmail: alertsEmailFlag, - AtlantisAllowList: fmt.Sprintf("%s/%s/*", cGitHost, cGitOwner), - AwsIamArnAccountRoot: fmt.Sprintf("arn:aws:iam::%s:root", *iamCaller.Account), - AwsNodeCapacityType: "ON_DEMAND", // todo adopt cli flag - AwsAccountID: *iamCaller.Account, - CloudProvider: awsinternal.CloudProvider, - CloudRegion: cloudRegionFlag, - ClusterName: clusterNameFlag, - ClusterType: clusterTypeFlag, - // DNSProvider: dnsProviderFlag, + AlertsEmail: alertsEmailFlag, + AtlantisAllowList: fmt.Sprintf("%s/%s/*", cGitHost, cGitOwner), + AwsIamArnAccountRoot: fmt.Sprintf("arn:aws:iam::%s:root", *iamCaller.Account), + AwsNodeCapacityType: "ON_DEMAND", // todo adopt cli flag + AwsAccountID: *iamCaller.Account, + CloudProvider: awsinternal.CloudProvider, + CloudRegion: cloudRegionFlag, + ClusterName: clusterNameFlag, + ClusterType: clusterTypeFlag, + DNSProvider: dnsProviderFlag, DomainName: domainNameFlag, KubeconfigPath: config.Kubeconfig, KubefirstArtifactsBucket: kubefirstArtifactsBucketName, @@ -602,6 +624,11 @@ func createAws(cmd *cobra.Command, args []string) error { KubefirstTeam: os.Getenv("KUBEFIRST_TEAM"), KubefirstVersion: configs.K1Version, + ExternalDNSProviderName: dnsProviderFlag, + ExternalDNSProviderTokenEnvName: externalDNSProviderTokenEnvName, + ExternalDNSProviderSecretName: fmt.Sprintf("%s-creds", awsinternal.CloudProvider), + ExternalDNSProviderSecretKey: externalDNSProviderSecretKey, + ArgoCDIngressURL: fmt.Sprintf("https://argocd.%s", domainNameFlag), ArgoCDIngressNoHTTPSURL: fmt.Sprintf("argocd.%s", domainNameFlag), ArgoWorkflowsIngressURL: fmt.Sprintf("https://argo.%s", domainNameFlag), @@ -641,7 +668,7 @@ func createAws(cmd *cobra.Command, args []string) error { ContainerRegistryURL: containerRegistryURL, } - metaphorTemplateTokens := providerConfigs.MetaphorTokenValues{ + metaphorDirectoryTokens := providerConfigs.MetaphorTokenValues{ ClusterName: clusterNameFlag, CloudRegion: cloudRegionFlag, ContainerRegistryURL: containerRegistryURL, @@ -651,6 +678,9 @@ func createAws(cmd *cobra.Command, args []string) error { MetaphorProductionIngressURL: fmt.Sprintf("metaphor-production.%s", domainNameFlag), } + config.GitOpsDirectoryValues = &gitopsDirectoryTokens + config.MetaphorDirectoryValues = &metaphorDirectoryTokens + //* git clone and detokenize the gitops repository progressPrinter.AddTracker("cloning-and-formatting-git-repositories", "Cloning and formatting git repositories", 1) progressPrinter.SetupProgress(progressPrinter.TotalOfTrackers(), false) @@ -676,7 +706,7 @@ func createAws(cmd *cobra.Command, args []string) error { config.K1Dir, &gitopsDirectoryTokens, config.MetaphorDir, - &metaphorTemplateTokens, + &metaphorDirectoryTokens, // Harecoded apex content to avoid creating apex resources for aws true, gitProtocolFlag, @@ -850,6 +880,7 @@ func createAws(cmd *cobra.Command, args []string) error { tfEntrypoint := config.GitopsDir + "/terraform/aws" tfEnvs := map[string]string{} + tfEnvs["TF_VAR_use_ecr"] = strconv.FormatBool(ecrFlag) tfEnvs["TF_VAR_aws_account_id"] = awsAccountID tfEnvs["TF_VAR_hosted_zone_name"] = domainNameFlag tfEnvs["AWS_SDK_LOAD_CONFIG"] = "1" @@ -1059,71 +1090,19 @@ func createAws(cmd *cobra.Command, args []string) error { if !executionControl { log.Info().Msg("Setting argocd username and password credentials") - log.Info().Msg("creating service accounts and namespaces") - err = bootstrap.ServiceAccounts(clientset) - if err != nil { - return err - } - - // swap secret data based on https flag - secretData := map[string][]byte{} - - if strings.Contains(config.DestinationGitopsRepoURL, "https") { - // http basic auth - secretData = map[string][]byte{ - "type": []byte("git"), - "name": []byte(fmt.Sprintf("%s-gitops", cGitOwner)), - "url": []byte(config.DestinationGitopsRepoURL), - "username": []byte(cGitUser), - "password": []byte(cGitToken), - } - } else { - // ssh - secretData = map[string][]byte{ - "type": []byte("git"), - "name": []byte(fmt.Sprintf("%s-gitops", cGitOwner)), - "url": []byte(config.DestinationGitopsRepoURL), - "sshPrivateKey": []byte(viper.GetString("kbot.private-key")), - } - } - secret := &v1.Secret{ - ObjectMeta: metav1.ObjectMeta{ - Name: "repo-credentials-template", - Namespace: "argocd", - Annotations: map[string]string{"managed-by": "argocd.argoproj.io"}, - Labels: map[string]string{"argocd.argoproj.io/secret-type": "repository"}, - }, - Data: secretData, - } - - _, err := clientset.CoreV1().Secrets(secret.ObjectMeta.Namespace).Get(context.TODO(), secret.ObjectMeta.Name, metav1.GetOptions{}) - if err == nil { - log.Info().Msgf("kubernetes secret %s/%s already created - skipping", secret.Namespace, secret.Name) - } else if strings.Contains(err.Error(), "not found") { - err := k8s.CreateSecretV2(clientset, secret) - if err != nil { - log.Info().Msgf("error creating kubernetes secret %s/%s: %s", secret.Namespace, secret.Name, err) - return err - } - log.Info().Msgf("created kubernetes secret: %s/%s", secret.Namespace, secret.Name) - } - - log.Info().Msg("secret create for argocd to connect to gitops repo") - - ecrToken, err := awsClient.GetECRAuthToken() - if err != nil { - return err - } - - dockerConfigString := fmt.Sprintf(`{"auths": {"%s": {"auth": "%s"}}}`, containerRegistryURL, ecrToken) - dockerCfgSecret := &v1.Secret{ - ObjectMeta: metav1.ObjectMeta{Name: "docker-config", Namespace: "argo"}, - Data: map[string][]byte{"config.json": []byte(dockerConfigString)}, - Type: "Opaque", - } - _, err = clientset.CoreV1().Secrets(dockerCfgSecret.ObjectMeta.Namespace).Create(context.TODO(), dockerCfgSecret, metav1.CreateOptions{}) + err := awsClient.BootstrapAwsMgmtCluster( + config.Kubeconfig, + config.GitProvider, + cGitUser, + os.Getenv("CF_API_TOKEN"), + config.DestinationGitopsRepoURL, + config.GitProtocol, + clientset, + ecrFlag, + containerRegistryURL, + ) if err != nil { - log.Info().Msgf("error creating kubernetes secret %s/%s: %s", dockerCfgSecret.Namespace, dockerCfgSecret.Name, err) + log.Info().Msg("Error adding kubernetes secrets for bootstrap") return err } @@ -1135,6 +1114,21 @@ func createAws(cmd *cobra.Command, args []string) error { progressPrinter.IncrementTracker("setting-up-eks-cluster", 1) } + // Container registry authentication creation + containerRegistryAuth := gitShim.ContainerRegistryAuth{ + GitProvider: gitProviderFlag, + GitUser: cGitUser, + GitToken: cGitToken, + GitlabGroupFlag: gitlabGroupFlag, + GithubOwner: cGitOwner, + ContainerRegistryHost: containerRegistryHost, + Clientset: clientset, + } + containerRegistryAuthToken, err := gitShim.CreateContainerRegistrySecret(&containerRegistryAuth) + if err != nil { + return err + } + var argocdPassword string //* argocd pods are ready, get and set credentials progressPrinter.AddTracker("creating-argocd-auth", "Creating Argo CD authentication", 1) @@ -1306,9 +1300,23 @@ func createAws(cmd *cobra.Command, args []string) error { log.Info().Msg("configuring vault with terraform") tfEnvs := map[string]string{} + var usernamePasswordString, base64DockerAuth string + + if config.GitProvider == "gitlab" { + usernamePasswordString = fmt.Sprintf("%s:%s", "container-registry-auth", containerRegistryAuthToken) + base64DockerAuth = base64.StdEncoding.EncodeToString([]byte(usernamePasswordString)) + + tfEnvs["TF_VAR_container_registry_auth"] = containerRegistryAuthToken + } else { + usernamePasswordString = fmt.Sprintf("%s:%s", cGitUser, cGitToken) + base64DockerAuth = base64.StdEncoding.EncodeToString([]byte(usernamePasswordString)) + } - usernamePasswordString := fmt.Sprintf("%s:%s", cGitUser, cGitToken) - base64DockerAuth := base64.StdEncoding.EncodeToString([]byte(usernamePasswordString)) + if viper.GetString("flags.dns-provider") == "cloudflare" { + tfEnvs[fmt.Sprintf("TF_VAR_%s_secret", gitopsDirectoryTokens.ExternalDNSProviderName)] = config.CloudflareAPIToken + } else { + tfEnvs[fmt.Sprintf("TF_VAR_%s_secret", gitopsDirectoryTokens.ExternalDNSProviderName)] = config.CivoToken + } tfEnvs["TF_VAR_email_address"] = "your@email.com" tfEnvs[fmt.Sprintf("TF_VAR_%s_token", config.GitProvider)] = cGitToken @@ -1322,9 +1330,6 @@ func createAws(cmd *cobra.Command, args []string) error { tfEnvs["TF_VAR_atlantis_repo_webhook_url"] = atlantisWebhookURL tfEnvs["TF_VAR_kbot_ssh_public_key"] = viper.GetString("kbot.public-key") tfEnvs["TF_VAR_kbot_ssh_private_key"] = viper.GetString("kbot.private-key") - if ecrFlag { - tfEnvs["TF_VAR_user_ecr"] = "true" - } // todo hyrdate a variable up top with these so we dont ref viper. if gitProviderFlag == "gitlab" { diff --git a/cmd/aws/destroy.go b/cmd/aws/destroy.go index 3509f192e..24187c13c 100644 --- a/cmd/aws/destroy.go +++ b/cmd/aws/destroy.go @@ -77,7 +77,14 @@ func destroyAws(cmd *cobra.Command, args []string) error { } // Instantiate aws config - config := providerConfigs.GetConfig(clusterName, domainName, gitProvider, cGitOwner, gitProtocol) + config := providerConfigs.GetConfig( + clusterName, + domainName, + gitProvider, + cGitOwner, + gitProtocol, + os.Getenv("CF_API_TOKEN"), + ) if len(cGitToken) == 0 { return fmt.Errorf( diff --git a/cmd/civo/backup.go b/cmd/civo/backup.go index 32e054329..8cb5fa9aa 100644 --- a/cmd/civo/backup.go +++ b/cmd/civo/backup.go @@ -36,7 +36,14 @@ func backupCivoSSL(cmd *cobra.Command, args []string) error { log.Panic().Msgf("invalid git provider option") } - config := providerConfigs.GetConfig(clusterName, domainName, gitProvider, cGitOwner, gitProtocol) + config := providerConfigs.GetConfig( + clusterName, + domainName, + gitProvider, + cGitOwner, + gitProtocol, + os.Getenv("CF_API_TOKEN"), + ) if _, err := os.Stat(config.SSLBackupDir + "/certificates"); os.IsNotExist(err) { // path/to/whatever does not exist diff --git a/cmd/civo/create.go b/cmd/civo/create.go index 7464f84ed..5d1493b0a 100644 --- a/cmd/civo/create.go +++ b/cmd/civo/create.go @@ -269,7 +269,14 @@ func createCivo(cmd *cobra.Command, args []string) error { } // Instantiate config - config := providerConfigs.GetConfig(clusterNameFlag, domainNameFlag, gitProviderFlag, cGitOwner, gitProtocolFlag) + config := providerConfigs.GetConfig( + clusterNameFlag, + domainNameFlag, + gitProviderFlag, + cGitOwner, + gitProtocolFlag, + os.Getenv("CF_API_TOKEN"), + ) config.CivoToken = os.Getenv("CIVO_TOKEN") switch gitProviderFlag { case "github": @@ -382,6 +389,8 @@ func createCivo(cmd *cobra.Command, args []string) error { viper.Set(fmt.Sprintf("%s.atlantis.webhook.url", config.GitProvider), fmt.Sprintf("https://atlantis.%s/events", domainNameFlag)) viper.WriteConfig() + config.GitOpsDirectoryValues = &gitopsDirectoryTokens + // Segment Client segmentClient := &segment.SegmentClient{ CliVersion: configs.K1Version, @@ -686,6 +695,8 @@ func createCivo(cmd *cobra.Command, args []string) error { MetaphorProductionIngressURL: fmt.Sprintf("metaphor-production.%s", domainNameFlag), } + config.MetaphorDirectoryValues = &metaphorDirectoryTokens + progressPrinter.AddTracker("cloning-and-formatting-git-repositories", "Cloning and formatting git repositories", 1) progressPrinter.SetupProgress(progressPrinter.TotalOfTrackers(), false) if !viper.GetBool("kubefirst-checks.gitops-ready-to-push") { diff --git a/cmd/civo/destroy.go b/cmd/civo/destroy.go index 534bc1612..c59815c18 100644 --- a/cmd/civo/destroy.go +++ b/cmd/civo/destroy.go @@ -69,7 +69,14 @@ func destroyCivo(cmd *cobra.Command, args []string) error { } // Instantiate civo config - config := providerConfigs.GetConfig(clusterName, domainName, gitProvider, cGitOwner, gitProtocol) + config := providerConfigs.GetConfig( + clusterName, + domainName, + gitProvider, + cGitOwner, + gitProtocol, + os.Getenv("CF_API_TOKEN"), + ) config.CivoToken = os.Getenv("CIVO_TOKEN") switch gitProvider { case "github": diff --git a/cmd/civo/root-credentials.go b/cmd/civo/root-credentials.go index 6df8e152e..7b20e4e55 100644 --- a/cmd/civo/root-credentials.go +++ b/cmd/civo/root-credentials.go @@ -8,6 +8,7 @@ package civo import ( "fmt" + "os" "github.com/kubefirst/runtime/pkg/civo" "github.com/kubefirst/runtime/pkg/credentials" @@ -55,7 +56,14 @@ func getCivoRootCredentials(cmd *cobra.Command, args []string) error { } // Instantiate kubernetes client - config := providerConfigs.GetConfig(clusterName, domainName, gitProvider, gitOwner, gitProtocol) + config := providerConfigs.GetConfig( + clusterName, + domainName, + gitProvider, + gitOwner, + gitProtocol, + os.Getenv("CF_API_TOKEN"), + ) kcfg := k8s.CreateKubeConfig(false, config.Kubeconfig) diff --git a/cmd/digitalocean/create.go b/cmd/digitalocean/create.go index 7b603a558..b0698786f 100644 --- a/cmd/digitalocean/create.go +++ b/cmd/digitalocean/create.go @@ -264,7 +264,14 @@ func createDigitalocean(cmd *cobra.Command, args []string) error { } // Instantiate config - config := providerConfigs.GetConfig(clusterNameFlag, domainNameFlag, gitProviderFlag, cGitOwner, gitProtocolFlag) + config := providerConfigs.GetConfig( + clusterNameFlag, + domainNameFlag, + gitProviderFlag, + cGitOwner, + gitProtocolFlag, + os.Getenv("CF_API_TOKEN"), + ) config.DigitaloceanToken = os.Getenv("DO_TOKEN") switch gitProviderFlag { case "github": @@ -497,45 +504,12 @@ func createDigitalocean(cmd *cobra.Command, args []string) error { return fmt.Errorf(msg) } - viper.Set("kubefirst-checks.domain-liveness", true) - viper.WriteConfig() - telemetryShim.Transmit(useTelemetryFlag, segmentClient, segment.MetricDomainLivenessCompleted, "") - progressPrinter.IncrementTracker("preflight-checks", 1) + case "cloudflare": // Implement a Cloudflare check at some point log.Info().Msg("domain check already complete - continuing") progressPrinter.IncrementTracker("preflight-checks", 1) } - - // verify dns - err := dns.VerifyProviderDNS(digitalocean.CloudProvider, cloudRegionFlag, domainNameFlag, nil) - if err != nil { - return err - } - - // domain id - domainId, err := digitaloceanConf.GetDNSInfo(domainNameFlag) - if err != nil { - log.Info().Msg(err.Error()) - } - - // viper values set in above function - log.Info().Msgf("domainId: %s", domainId) - // domainLiveness := digitaloceanConf.TestDomainLiveness(domainNameFlag) - // if !domainLiveness { - // telemetryShim.Transmit(useTelemetryFlag, segmentClient, segment.MetricDomainLivenessFailed, "domain liveness test failed") - // msg := "failed to check the liveness of the Domain. A valid public Domain on the same digitalocean " + - // "account as the one where Kubefirst will be installed is required for this operation to " + - // "complete.\nTroubleshoot Steps:\n\n - Make sure you are using the correct digitalocean account and " + - // "region.\n - Verify that you have the necessary permissions to access the domain.\n - Check " + - // "that the domain is correctly configured and is a public domain\n - Check if the " + - // "domain exists and has the correct name and domain.\n - If you don't have a Domain," + - // "please follow these instructions to create one: " + - // "https://docs.digitalocean.com/products/networking/dns/how-to/ \n\n" + - // "if you are still facing issues please reach out to support team for further assistance" - - // return fmt.Errorf(msg) - // } viper.Set("kubefirst-checks.domain-liveness", true) viper.WriteConfig() telemetryShim.Transmit(useTelemetryFlag, segmentClient, segment.MetricDomainLivenessCompleted, "") @@ -701,6 +675,8 @@ func createDigitalocean(cmd *cobra.Command, args []string) error { MetaphorProductionIngressURL: fmt.Sprintf("metaphor-production.%s", domainNameFlag), } + config.GitOpsDirectoryValues = &gitopsDirectoryTokens + config.MetaphorDirectoryValues = &metaphorDirectoryTokens //* git clone and detokenize the gitops repository // todo improve this logic for removing `kubefirst clean` // if !viper.GetBool("template-repo.gitops.cloned") || viper.GetBool("template-repo.gitops.removed") { diff --git a/cmd/digitalocean/destroy.go b/cmd/digitalocean/destroy.go index 0fc8064a1..1eb643c05 100644 --- a/cmd/digitalocean/destroy.go +++ b/cmd/digitalocean/destroy.go @@ -64,7 +64,14 @@ func destroyDigitalocean(cmd *cobra.Command, args []string) error { } // Instantiate digitalocean config - config := providerConfigs.GetConfig(clusterName, domainName, gitProvider, cGitOwner, gitProtocol) + config := providerConfigs.GetConfig( + clusterName, + domainName, + gitProvider, + cGitOwner, + gitProtocol, + os.Getenv("CF_API_TOKEN"), + ) config.DigitaloceanToken = os.Getenv("DO_TOKEN") switch gitProvider { case "github": diff --git a/cmd/digitalocean/root-credentials.go b/cmd/digitalocean/root-credentials.go index 75d639437..0d0cbb71e 100644 --- a/cmd/digitalocean/root-credentials.go +++ b/cmd/digitalocean/root-credentials.go @@ -8,6 +8,7 @@ package digitalocean import ( "fmt" + "os" "github.com/kubefirst/runtime/pkg/credentials" "github.com/kubefirst/runtime/pkg/digitalocean" @@ -55,7 +56,14 @@ func getDigitaloceanRootCredentials(cmd *cobra.Command, args []string) error { } // Instantiate kubernetes client - config := providerConfigs.GetConfig(clusterName, domainName, gitProvider, gitOwner, gitProtocol) + config := providerConfigs.GetConfig( + clusterName, + domainName, + gitProvider, + gitOwner, + gitProtocol, + os.Getenv("CF_API_TOKEN"), + ) kcfg := k8s.CreateKubeConfig(false, config.Kubeconfig) diff --git a/cmd/gcp/command.go b/cmd/gcp/command.go index 3e4f581fc..e86304d59 100644 --- a/cmd/gcp/command.go +++ b/cmd/gcp/command.go @@ -14,12 +14,12 @@ import ( var ( // Create - alertsEmailFlag string - ciFlag bool - cloudRegionFlag string - clusterNameFlag string - clusterTypeFlag string - // dnsProviderFlag string + alertsEmailFlag string + ciFlag bool + cloudRegionFlag string + clusterNameFlag string + clusterTypeFlag string + dnsProviderFlag string domainNameFlag string gcpProjectFlag string githubOrgFlag string @@ -74,7 +74,7 @@ func Create() *cobra.Command { createCmd.Flags().StringVar(&cloudRegionFlag, "cloud-region", "us-east1", "the GCP region to provision infrastructure in") createCmd.Flags().StringVar(&clusterNameFlag, "cluster-name", "kubefirst", "the name of the cluster to create") createCmd.Flags().StringVar(&clusterTypeFlag, "cluster-type", "mgmt", "the type of cluster to create (i.e. mgmt|workload)") - // createCmd.Flags().StringVar(&dnsProviderFlag, "dns-provider", "gcp", fmt.Sprintf("the dns provider - one of: %s", supportedDNSProviders)) + createCmd.Flags().StringVar(&dnsProviderFlag, "dns-provider", "gcp", fmt.Sprintf("the dns provider - one of: %s", supportedDNSProviders)) createCmd.Flags().StringVar(&domainNameFlag, "domain-name", "", "the GCP DNS Name to use for DNS records (i.e. your-domain.com|subdomain.your-domain.com) (required)") createCmd.MarkFlagRequired("domain-name") createCmd.Flags().StringVar(&gcpProjectFlag, "gcp-project", "", "gcp project id (required)") diff --git a/cmd/gcp/create.go b/cmd/gcp/create.go index 1c6a907b0..1d1ad30d1 100644 --- a/cmd/gcp/create.go +++ b/cmd/gcp/create.go @@ -76,10 +76,10 @@ func createGCP(cmd *cobra.Command, args []string) error { return err } - // dnsProviderFlag, err := cmd.Flags().GetString("dns-provider") - // if err != nil { - // return err - // } + dnsProviderFlag, err := cmd.Flags().GetString("dns-provider") + if err != nil { + return err + } domainNameFlag, err := cmd.Flags().GetString("domain-name") if err != nil { @@ -156,7 +156,7 @@ func createGCP(cmd *cobra.Command, args []string) error { // required for destroy command viper.Set("flags.alerts-email", alertsEmailFlag) viper.Set("flags.cluster-name", clusterNameFlag) - // viper.Set("flags.dns-provider", dnsProviderFlag) + viper.Set("flags.dns-provider", dnsProviderFlag) viper.Set("flags.domain-name", domainNameFlag) viper.Set("flags.git-provider", gitProviderFlag) viper.Set("flags.cloud-region", cloudRegionFlag) @@ -254,7 +254,14 @@ func createGCP(cmd *cobra.Command, args []string) error { } // Instantiate config - config := providerConfigs.GetConfig(clusterNameFlag, domainNameFlag, gitProviderFlag, cGitOwner, gitProtocolFlag) + config := providerConfigs.GetConfig( + clusterNameFlag, + domainNameFlag, + gitProviderFlag, + cGitOwner, + gitProtocolFlag, + os.Getenv("CF_API_TOKEN"), + ) // This is the environment variable required to create and is set to the path of the service account json file // This gets read for terraform applies and is applied as a variable containing the contents of the file // This is otherwise leveraged by the runtime to provide application default credentials to the GCP go SDK/API @@ -299,13 +306,13 @@ func createGCP(cmd *cobra.Command, args []string) error { } gitopsDirectoryTokens := providerConfigs.GitOpsDirectoryValues{ - AlertsEmail: alertsEmailFlag, - AtlantisAllowList: fmt.Sprintf("%s/%s/*", cGitHost, cGitOwner), - CloudProvider: gcp.CloudProvider, - CloudRegion: cloudRegionFlag, - ClusterName: clusterNameFlag, - ClusterType: clusterTypeFlag, - // DNSProvider: dnsProviderFlag, + AlertsEmail: alertsEmailFlag, + AtlantisAllowList: fmt.Sprintf("%s/%s/*", cGitHost, cGitOwner), + CloudProvider: gcp.CloudProvider, + CloudRegion: cloudRegionFlag, + ClusterName: clusterNameFlag, + ClusterType: clusterTypeFlag, + DNSProvider: dnsProviderFlag, DomainName: domainNameFlag, KubeconfigPath: config.Kubeconfig, KubefirstArtifactsBucket: kubefirstArtifactsBucketName, @@ -430,46 +437,46 @@ func createGCP(cmd *cobra.Command, args []string) error { if !skipDomainCheck { telemetryShim.Transmit(useTelemetryFlag, segmentClient, segment.MetricDomainLivenessStarted, "") - // switch dnsProviderFlag { - // case "gcp": - gcpConf := gcp.GCPConfiguration{ - Context: context.Background(), - Project: gcpProjectFlag, - Region: cloudRegionFlag, - } + switch dnsProviderFlag { + case "gcp": + gcpConf := gcp.GCPConfiguration{ + Context: context.Background(), + Project: gcpProjectFlag, + Region: cloudRegionFlag, + } - // verify dns - // TODO: update to work with gcp? - //err := dns.VerifyProviderDNS(gcp.CloudProvider, cloudRegionFlag, domainNameFlag) - //if err != nil { - // return err - //} - - // viper values set in above function - domainLiveness := gcpConf.TestHostedZoneLiveness(domainNameFlag) - if !domainLiveness { - telemetryShim.Transmit(useTelemetryFlag, segmentClient, segment.MetricDomainLivenessFailed, "domain liveness test failed") - msg := "failed to check the liveness of the Domain. A valid public Domain on the same GCP " + - "account as the one where Kubefirst will be installed is required for this operation to " + - "complete.\nTroubleshoot Steps:\n\n - Make sure you are using the correct GCP project and " + - "region.\n - Verify that you have the necessary permissions to access the domain.\n - Check " + - "that the domain is correctly configured and is a public domain\n - Check if the " + - "domain exists and has the correct name and domain.\n - If you don't have a Domain," + - "please follow these instructions to create one: " + - "https://cloud.google.com/dns/docs/tutorials/create-domain-tutorial \n\n" + - "if you are still facing issues please reach out to the support team for further assistance" + // verify dns + // TODO: update to work with gcp? + //err := dns.VerifyProviderDNS(gcp.CloudProvider, cloudRegionFlag, domainNameFlag) + //if err != nil { + // return err + //} + + // viper values set in above function + domainLiveness := gcpConf.TestHostedZoneLiveness(domainNameFlag) + if !domainLiveness { + telemetryShim.Transmit(useTelemetryFlag, segmentClient, segment.MetricDomainLivenessFailed, "domain liveness test failed") + msg := "failed to check the liveness of the Domain. A valid public Domain on the same GCP " + + "account as the one where Kubefirst will be installed is required for this operation to " + + "complete.\nTroubleshoot Steps:\n\n - Make sure you are using the correct GCP project and " + + "region.\n - Verify that you have the necessary permissions to access the domain.\n - Check " + + "that the domain is correctly configured and is a public domain\n - Check if the " + + "domain exists and has the correct name and domain.\n - If you don't have a Domain," + + "please follow these instructions to create one: " + + "https://cloud.google.com/dns/docs/tutorials/create-domain-tutorial \n\n" + + "if you are still facing issues please reach out to the support team for further assistance" - return fmt.Errorf(msg) + return fmt.Errorf(msg) + } + viper.Set("kubefirst-checks.domain-liveness", true) + viper.WriteConfig() + telemetryShim.Transmit(useTelemetryFlag, segmentClient, segment.MetricDomainLivenessCompleted, "") + progressPrinter.IncrementTracker("preflight-checks", 1) + case "cloudflare": + // Implement a Cloudflare check at some point + log.Info().Msg("domain check already complete - continuing") + progressPrinter.IncrementTracker("preflight-checks", 1) } - viper.Set("kubefirst-checks.domain-liveness", true) - viper.WriteConfig() - telemetryShim.Transmit(useTelemetryFlag, segmentClient, segment.MetricDomainLivenessCompleted, "") - progressPrinter.IncrementTracker("preflight-checks", 1) - // case "cloudflare": - // // Implement a Cloudflare check at some point - // log.Info().Msg("domain check already complete - continuing") - // progressPrinter.IncrementTracker("preflight-checks", 1) - // } } else { log.Info().Msg("domain check already complete - continuing") progressPrinter.IncrementTracker("preflight-checks", 1) @@ -631,6 +638,8 @@ func createGCP(cmd *cobra.Command, args []string) error { MetaphorProductionIngressURL: fmt.Sprintf("metaphor-production.%s", domainNameFlag), } + config.GitOpsDirectoryValues = &gitopsDirectoryTokens + config.MetaphorDirectoryValues = &metaphorDirectoryTokens //* git clone and detokenize the gitops repository progressPrinter.AddTracker("cloning-and-formatting-git-repositories", "Cloning and formatting git repositories", 1) @@ -642,6 +651,21 @@ func createGCP(cmd *cobra.Command, args []string) error { // These need to be set for reference elsewhere viper.Set(fmt.Sprintf("%s.repos.gitops.git-url", config.GitProvider), config.DestinationGitopsRepoHttpsURL) viper.WriteConfig() + + var externalDNSProviderTokenEnvName, externalDNSProviderSecretKey string + if dnsProviderFlag == "cloudflare" { + externalDNSProviderTokenEnvName = "CF_API_TOKEN" + externalDNSProviderSecretKey = "cf-api-token" + } else { + externalDNSProviderTokenEnvName = "GCP_AUTH" + externalDNSProviderSecretKey = fmt.Sprintf("%s-token", gcp.CloudProvider) + } + + gitopsDirectoryTokens.ExternalDNSProviderName = dnsProviderFlag + gitopsDirectoryTokens.ExternalDNSProviderTokenEnvName = externalDNSProviderTokenEnvName + gitopsDirectoryTokens.ExternalDNSProviderSecretName = fmt.Sprintf("%s-creds", gcp.CloudProvider) + gitopsDirectoryTokens.ExternalDNSProviderSecretKey = externalDNSProviderSecretKey + gitopsDirectoryTokens.GitOpsRepoGitURL = config.DestinationGitopsRepoHttpsURL // Determine if anything exists at domain apex @@ -883,7 +907,16 @@ func createGCP(cmd *cobra.Command, args []string) error { progressPrinter.SetupProgress(progressPrinter.TotalOfTrackers(), false) executionControl = viper.GetBool("kubefirst-checks.k8s-secrets-created") if !executionControl { - err := gcp.BootstrapGCPMgmtCluster(kcfg.Clientset, config.GitProvider, cGitUser, config.DestinationGitopsRepoURL, config.GitProtocol) + err := gcp.BootstrapGCPMgmtCluster( + kcfg.Clientset, + config.GitProvider, + cGitUser, + config.DestinationGitopsRepoURL, + config.GitProtocol, + os.Getenv("CF_API_TOKEN"), + config.GCPAuth, + ) + if err != nil { log.Info().Msg("Error adding kubernetes secrets for bootstrap") return err diff --git a/cmd/gcp/destroy.go b/cmd/gcp/destroy.go index c5d0cabe3..2a2f40539 100644 --- a/cmd/gcp/destroy.go +++ b/cmd/gcp/destroy.go @@ -66,7 +66,14 @@ func destroyGCP(cmd *cobra.Command, args []string) error { } // Instantiate GCP config - config := providerConfigs.GetConfig(clusterName, domainName, gitProvider, cGitOwner, gitProtocol) + config := providerConfigs.GetConfig( + clusterName, + domainName, + gitProvider, + cGitOwner, + gitProtocol, + os.Getenv("CF_API_TOKEN"), + ) // This is the environment variable required to create and is set to the path of the service account json file // This gets read for terraform applies and is applied as a variable containing the contents of the file // This is otherwise leveraged by the runtime to provide application default credentials to the GCP go SDK/API diff --git a/cmd/vultr/create.go b/cmd/vultr/create.go index 69101412d..b51a4bf74 100644 --- a/cmd/vultr/create.go +++ b/cmd/vultr/create.go @@ -269,7 +269,14 @@ func createVultr(cmd *cobra.Command, args []string) error { } // Instantiate config - config := providerConfigs.GetConfig(clusterNameFlag, domainNameFlag, gitProviderFlag, cGitOwner, gitProtocolFlag) + config := providerConfigs.GetConfig( + clusterNameFlag, + domainNameFlag, + gitProviderFlag, + cGitOwner, + gitProtocolFlag, + os.Getenv("CF_API_TOKEN"), + ) config.VultrToken = os.Getenv("VULTR_API_KEY") switch gitProviderFlag { case "github": @@ -670,6 +677,8 @@ func createVultr(cmd *cobra.Command, args []string) error { MetaphorProductionIngressURL: fmt.Sprintf("metaphor-production.%s", domainNameFlag), } + config.GitOpsDirectoryValues = &gitopsDirectoryTokens + config.MetaphorDirectoryValues = &metaphorDirectoryTokens //* git clone and detokenize the gitops repository // todo improve this logic for removing `kubefirst clean` diff --git a/cmd/vultr/destroy.go b/cmd/vultr/destroy.go index 69b69694a..c50acb83a 100644 --- a/cmd/vultr/destroy.go +++ b/cmd/vultr/destroy.go @@ -68,7 +68,14 @@ func destroyVultr(cmd *cobra.Command, args []string) error { } // Instantiate vultr config - config := providerConfigs.GetConfig(clusterName, domainName, gitProvider, cGitOwner, gitProtocolFlag) + config := providerConfigs.GetConfig( + clusterName, + domainName, + gitProvider, + cGitOwner, + gitProtocolFlag, + os.Getenv("CF_API_TOKEN"), + ) config.VultrToken = os.Getenv("VULTR_API_KEY") switch gitProvider { case "github": diff --git a/cmd/vultr/root-credentials.go b/cmd/vultr/root-credentials.go index 253a439ab..a1610664f 100644 --- a/cmd/vultr/root-credentials.go +++ b/cmd/vultr/root-credentials.go @@ -8,6 +8,7 @@ package vultr import ( "fmt" + "os" "github.com/kubefirst/runtime/pkg/credentials" "github.com/kubefirst/runtime/pkg/k8s" @@ -55,7 +56,14 @@ func getVultrRootCredentials(cmd *cobra.Command, args []string) error { } // Instantiate kubernetes client - config := providerConfigs.GetConfig(clusterName, domainName, gitProvider, gitOwner, gitProtocol) + config := providerConfigs.GetConfig( + clusterName, + domainName, + gitProvider, + gitOwner, + gitProtocol, + os.Getenv("CF_API_TOKEN"), + ) kcfg := k8s.CreateKubeConfig(false, config.Kubeconfig) diff --git a/go.mod b/go.mod index 51ee74123..9ce1c0f53 100644 --- a/go.mod +++ b/go.mod @@ -14,7 +14,7 @@ require ( github.com/dustin/go-humanize v1.0.1 github.com/go-git/go-git/v5 v5.6.1 github.com/hashicorp/vault/api v1.9.0 - github.com/kubefirst/runtime v0.2.9 + github.com/kubefirst/runtime v0.2.10 github.com/rs/zerolog v1.29.0 github.com/sirupsen/logrus v1.9.0 github.com/spf13/cobra v1.7.0 diff --git a/go.sum b/go.sum index df30fb429..c5020bc21 100644 --- a/go.sum +++ b/go.sum @@ -714,8 +714,8 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/kubefirst/runtime v0.2.9 h1:S7eJfcxPSRdNK8lKeHemxquNWF2DgnqFrm8KjrV85So= -github.com/kubefirst/runtime v0.2.9/go.mod h1:YAww60f+GxyYZIBzJxuqpf8yzfmsRBS0Zr0QiTD7aTE= +github.com/kubefirst/runtime v0.2.10 h1:HttcQweYck903QQwY0EjSg2gH76tOq44BMlOnxRjMMU= +github.com/kubefirst/runtime v0.2.10/go.mod h1:YAww60f+GxyYZIBzJxuqpf8yzfmsRBS0Zr0QiTD7aTE= github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/ledongthuc/pdf v0.0.0-20220302134840-0c2507a12d80 h1:6Yzfa6GP0rIo/kULo2bwGEkFvCePZ3qHDDTC3/J9Swo=