Skip to content

Commit

Permalink
feat(azure): create azure cluster (#428)
Browse files Browse the repository at this point in the history
* chore(devcontainer): set kubeconfig envvar

* feat(azure): create azure cluster

* feat(azure): retrieve the storage access keys

* azure config for vault terraform

* fix: lint things

* ci: ignore g115 errors in golangci

There's no realistic way of avoiding this error in Golang so it
doesn't add much value

* chore: increase cyclo complexity

Necessary to keep the pattern of how the router works. This
should be refactored so not required
  • Loading branch information
mrsimonemms authored Nov 5, 2024
1 parent 175e41b commit ca1b5ca
Show file tree
Hide file tree
Showing 34 changed files with 1,057 additions and 31 deletions.
1 change: 1 addition & 0 deletions .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
"K1_ACCESS_TOKEN": "feedkray",
"K1_LOCAL_DEBUG": "true",
"K1_LOCAL_KUBECONFIG_PATH": "/home/vscode/.config/k3d/kubeconfig-dev.yaml",
"KUBECONFIG": "/home/vscode/.config/k3d/kubeconfig-dev.yaml",
"KUBEFIRST_TEAM": "true"
}
}
3 changes: 2 additions & 1 deletion .golangci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -103,14 +103,15 @@ linters-settings:
- G110 # Decompression bombs: we can check these manually when submitting code
- G306 # Poor file permissions used when creating a directory: we can check these manually when submitting code
- G404 # Use of weak random number generator (math/rand instead of crypto/rand): we can live with these
- G115 # No realistic way of avoiding this in Go when converting from int to uint

stylecheck:
checks:
- "all"
- "-ST1003" # this is covered by a different linter

gocyclo:
min-complexity: 60
min-complexity: 68

exhaustive:
check-generated: false
Expand Down
32 changes: 32 additions & 0 deletions docs/docs.go
Original file line number Diff line number Diff line change
Expand Up @@ -1013,6 +1013,23 @@ const docTemplate = `{
}
}
},
"types.AzureAuth": {
"type": "object",
"properties": {
"client_id": {
"type": "string"
},
"client_secret": {
"type": "string"
},
"subscription_id": {
"type": "string"
},
"tenant_id": {
"type": "string"
}
}
},
"types.CivoAuth": {
"type": "object",
"properties": {
Expand Down Expand Up @@ -1114,6 +1131,13 @@ const docTemplate = `{
"aws_kms_key_id": {
"type": "string"
},
"azure_auth": {
"$ref": "#/definitions/types.AzureAuth"
},
"azure_dns_zone_resource_group": {
"description": "Azure",
"type": "string"
},
"civo_auth": {
"$ref": "#/definitions/types.CivoAuth"
},
Expand Down Expand Up @@ -1309,6 +1333,13 @@ const docTemplate = `{
"aws_auth": {
"$ref": "#/definitions/types.AWSAuth"
},
"azure_auth": {
"$ref": "#/definitions/types.AzureAuth"
},
"azure_dns_zone_resource_group": {
"description": "Azure",
"type": "string"
},
"civo_auth": {
"$ref": "#/definitions/types.CivoAuth"
},
Expand All @@ -1317,6 +1348,7 @@ const docTemplate = `{
"enum": [
"akamai",
"aws",
"azure",
"civo",
"digitalocean",
"google",
Expand Down
32 changes: 32 additions & 0 deletions docs/swagger.json
Original file line number Diff line number Diff line change
Expand Up @@ -1007,6 +1007,23 @@
}
}
},
"types.AzureAuth": {
"type": "object",
"properties": {
"client_id": {
"type": "string"
},
"client_secret": {
"type": "string"
},
"subscription_id": {
"type": "string"
},
"tenant_id": {
"type": "string"
}
}
},
"types.CivoAuth": {
"type": "object",
"properties": {
Expand Down Expand Up @@ -1108,6 +1125,13 @@
"aws_kms_key_id": {
"type": "string"
},
"azure_auth": {
"$ref": "#/definitions/types.AzureAuth"
},
"azure_dns_zone_resource_group": {
"description": "Azure",
"type": "string"
},
"civo_auth": {
"$ref": "#/definitions/types.CivoAuth"
},
Expand Down Expand Up @@ -1303,6 +1327,13 @@
"aws_auth": {
"$ref": "#/definitions/types.AWSAuth"
},
"azure_auth": {
"$ref": "#/definitions/types.AzureAuth"
},
"azure_dns_zone_resource_group": {
"description": "Azure",
"type": "string"
},
"civo_auth": {
"$ref": "#/definitions/types.CivoAuth"
},
Expand All @@ -1311,6 +1342,7 @@
"enum": [
"akamai",
"aws",
"azure",
"civo",
"digitalocean",
"google",
Expand Down
22 changes: 22 additions & 0 deletions docs/swagger.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,17 @@ definitions:
token:
type: string
type: object
types.AzureAuth:
properties:
client_id:
type: string
client_secret:
type: string
subscription_id:
type: string
tenant_id:
type: string
type: object
types.CivoAuth:
properties:
token:
Expand Down Expand Up @@ -82,6 +93,11 @@ definitions:
type: boolean
aws_kms_key_id:
type: string
azure_auth:
$ref: '#/definitions/types.AzureAuth'
azure_dns_zone_resource_group:
description: Azure
type: string
civo_auth:
$ref: '#/definitions/types.CivoAuth'
cloud_provider:
Expand Down Expand Up @@ -207,12 +223,18 @@ definitions:
description: Auth
aws_auth:
$ref: '#/definitions/types.AWSAuth'
azure_auth:
$ref: '#/definitions/types.AzureAuth'
azure_dns_zone_resource_group:
description: Azure
type: string
civo_auth:
$ref: '#/definitions/types.CivoAuth'
cloud_provider:
enum:
- akamai
- aws
- azure
- civo
- digitalocean
- google
Expand Down
109 changes: 109 additions & 0 deletions extensions/azure/env.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
package azure

import (
"fmt"
"log"
"strconv"
"strings"

"github.com/konstructio/kubefirst-api/internal/vault"
"github.com/konstructio/kubefirst-api/pkg/k8s"
"github.com/konstructio/kubefirst-api/pkg/providerConfigs"
pkgtypes "github.com/konstructio/kubefirst-api/pkg/types"
"k8s.io/client-go/kubernetes"
)

func readVaultTokenFromSecret(clientset kubernetes.Interface) string {
existingKubernetesSecret, err := k8s.ReadSecretV2(clientset, vault.VaultNamespace, vault.VaultSecretName)
if err != nil || existingKubernetesSecret == nil {
log.Printf("Error reading existing Secret data: %s", err)
return ""
}

return existingKubernetesSecret["root-token"]
}

func GetAzureTerraformEnvs(envs map[string]string, cl *pkgtypes.Cluster) map[string]string {
envs["ARM_CLIENT_ID"] = cl.AzureAuth.ClientID
envs["ARM_CLIENT_SECRET"] = cl.AzureAuth.ClientSecret
envs["ARM_TENANT_ID"] = cl.AzureAuth.TenantID
envs["ARM_SUBSCRIPTION_ID"] = cl.AzureAuth.SubscriptionID
envs["TF_VAR_arm_client_id"] = cl.AzureAuth.ClientID
envs["TF_VAR_arm_client_secret"] = cl.AzureAuth.ClientSecret
envs["TF_VAR_arm_tenant_id"] = cl.AzureAuth.TenantID
envs["TF_VAR_arm_subscription_id"] = cl.AzureAuth.SubscriptionID
envs["TF_VAR_azure_storage_account"] = cl.StateStoreCredentials.Name
envs["TF_VAR_azure_storage_access_key"] = cl.StateStoreCredentials.SecretAccessKey

return envs
}

func GetGithubTerraformEnvs(envs map[string]string, cl *pkgtypes.Cluster) map[string]string {
envs["GITHUB_TOKEN"] = cl.GitAuth.Token
envs["GITHUB_OWNER"] = cl.GitAuth.Owner
envs["TF_VAR_atlantis_repo_webhook_secret"] = cl.AtlantisWebhookSecret
envs["TF_VAR_kbot_ssh_public_key"] = cl.GitAuth.PublicKey
envs["ARM_CLIENT_ID"] = cl.AzureAuth.ClientID
envs["ARM_CLIENT_SECRET"] = cl.AzureAuth.ClientSecret
envs["ARM_TENANT_ID"] = cl.AzureAuth.TenantID
envs["ARM_SUBSCRIPTION_ID"] = cl.AzureAuth.SubscriptionID

return envs
}

func GetGitlabTerraformEnvs(envs map[string]string, gid int, cl *pkgtypes.Cluster) map[string]string {
envs["GITLAB_TOKEN"] = cl.GitAuth.Token
envs["GITLAB_OWNER"] = cl.GitAuth.Owner
envs["TF_VAR_atlantis_repo_webhook_secret"] = cl.AtlantisWebhookSecret
envs["TF_VAR_atlantis_repo_webhook_url"] = cl.AtlantisWebhookURL
envs["TF_VAR_kbot_ssh_public_key"] = cl.GitAuth.PublicKey
envs["ARM_CLIENT_ID"] = cl.AzureAuth.ClientID
envs["ARM_CLIENT_SECRET"] = cl.AzureAuth.ClientSecret
envs["ARM_TENANT_ID"] = cl.AzureAuth.TenantID
envs["ARM_SUBSCRIPTION_ID"] = cl.AzureAuth.SubscriptionID
envs["TF_VAR_owner_group_id"] = strconv.Itoa(gid)
envs["TF_VAR_gitlab_owner"] = cl.GitAuth.Owner

return envs
}

func GetUsersTerraformEnvs(clientset kubernetes.Interface, cl *pkgtypes.Cluster, envs map[string]string) map[string]string {
envs["VAULT_TOKEN"] = readVaultTokenFromSecret(clientset)
envs["VAULT_ADDR"] = providerConfigs.VaultPortForwardURL
envs[fmt.Sprintf("%s_TOKEN", strings.ToUpper(cl.GitProvider))] = cl.GitAuth.Token
envs[fmt.Sprintf("%s_OWNER", strings.ToUpper(cl.GitProvider))] = cl.GitAuth.Owner
envs["ARM_CLIENT_ID"] = cl.AzureAuth.ClientID
envs["ARM_CLIENT_SECRET"] = cl.AzureAuth.ClientSecret
envs["ARM_TENANT_ID"] = cl.AzureAuth.TenantID
envs["ARM_SUBSCRIPTION_ID"] = cl.AzureAuth.SubscriptionID

return envs
}

func GetVaultTerraformEnvs(clientset kubernetes.Interface, cl *pkgtypes.Cluster, envs map[string]string) map[string]string {
envs[fmt.Sprintf("%s_TOKEN", strings.ToUpper(cl.GitProvider))] = cl.GitAuth.Token
envs[fmt.Sprintf("%s_OWNER", strings.ToUpper(cl.GitProvider))] = cl.GitAuth.Owner
envs["TF_VAR_email_address"] = cl.AlertsEmail
envs["TF_VAR_vault_addr"] = providerConfigs.VaultPortForwardURL
envs["TF_VAR_vault_token"] = readVaultTokenFromSecret(clientset)
envs[fmt.Sprintf("TF_VAR_%s_token", cl.GitProvider)] = cl.GitAuth.Token
envs["VAULT_ADDR"] = providerConfigs.VaultPortForwardURL
envs["VAULT_TOKEN"] = readVaultTokenFromSecret(clientset)
envs["TF_VAR_civo_token"] = cl.CivoAuth.Token
envs["TF_VAR_atlantis_repo_webhook_secret"] = cl.AtlantisWebhookSecret
envs["TF_VAR_atlantis_repo_webhook_url"] = cl.AtlantisWebhookURL
envs["TF_VAR_kbot_ssh_private_key"] = cl.GitAuth.PrivateKey
envs["TF_VAR_kbot_ssh_public_key"] = cl.GitAuth.PublicKey
envs["TF_VAR_cloudflare_origin_ca_api_key"] = cl.CloudflareAuth.OriginCaIssuerKey
envs["TF_VAR_cloudflare_api_key"] = cl.CloudflareAuth.APIToken
envs["ARM_CLIENT_ID"] = cl.AzureAuth.ClientID
envs["ARM_CLIENT_SECRET"] = cl.AzureAuth.ClientSecret
envs["ARM_TENANT_ID"] = cl.AzureAuth.TenantID
envs["ARM_SUBSCRIPTION_ID"] = cl.AzureAuth.SubscriptionID

if cl.GitProvider == "gitlab" {
envs["TF_VAR_owner_group_id"] = fmt.Sprint(cl.GitlabOwnerGroupID)
}

return envs
}
36 changes: 36 additions & 0 deletions extensions/azure/secrets.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package azure

import (
"fmt"

providerConfig "github.com/konstructio/kubefirst-api/pkg/providerConfigs"
pkgtypes "github.com/konstructio/kubefirst-api/pkg/types"
"github.com/rs/zerolog/log"
"k8s.io/client-go/kubernetes"
)

func BootstrapAzureMgmtCluster(clientset kubernetes.Interface, cl *pkgtypes.Cluster, destinationGitopsRepoURL string) error {
opts := providerConfig.BootstrapOptions{
GitUser: cl.GitAuth.User,
DestinationGitopsRepoURL: destinationGitopsRepoURL,
GitProtocol: cl.GitProtocol,
CloudflareAPIToken: cl.CloudflareAuth.APIToken,
DNSProvider: cl.DNSProvider,
CloudProvider: cl.CloudProvider,
HTTPSPassword: cl.GitAuth.Token,
SSHToken: cl.GitAuth.PrivateKey,
}

if err := providerConfig.BootstrapMgmtCluster(clientset, opts); err != nil {
log.Error().Msgf("unable to bootstrap management cluster: %s", err)
return fmt.Errorf("unable to bootstrap management cluster: %w", err)
}

// Create secrets
if err := providerConfig.BootstrapSecrets(clientset, cl); err != nil {
log.Error().Msgf("unable to bootstrap secrets: %s", err)
return fmt.Errorf("unable to bootstrap secrets: %w", err)
}

return nil
}
Loading

0 comments on commit ca1b5ca

Please sign in to comment.