diff --git a/.gitignore b/.gitignore index fba43ea..69e2ad7 100644 --- a/.gitignore +++ b/.gitignore @@ -4,4 +4,4 @@ *artifacts* *k8s-admin* vault-keys.json -*config.yaml* \ No newline at end of file +config.yaml \ No newline at end of file diff --git a/cmd/main/main.go b/cmd/main/main.go index 974d767..bd886b7 100644 --- a/cmd/main/main.go +++ b/cmd/main/main.go @@ -2,9 +2,9 @@ package main import ( "flag" - "kube-forge/pkg/config" - "kube-forge/pkg/kubespray" - "kube-forge/pkg/templates" + "kube-forge/internal/config" + "kube-forge/internal/kubespray" + "kube-forge/internal/templates" "os" ) diff --git a/config.sample.yaml b/config.sample.yaml index df671ac..860efb5 100644 --- a/config.sample.yaml +++ b/config.sample.yaml @@ -191,6 +191,11 @@ modules: rollouts: enabled: true + ha: + enabled: true + expose: + type: "NodePort" # now only NodePort supported + node_port: 30010 updates_operator: enabled: true @@ -245,9 +250,6 @@ modules: redis_size: 1Gi trivy_size: 5Gi - defaultProjects: - - name: harbor-helm - public: false enabled_scanner: true additional: diff --git a/examples/rollouts-app-test.yaml b/examples/rollouts-app-test.yaml new file mode 100644 index 0000000..dbb7a74 --- /dev/null +++ b/examples/rollouts-app-test.yaml @@ -0,0 +1,65 @@ +apiVersion: v1 +kind: Service +metadata: + name: canary-demo-preview +spec: + ports: + - port: 80 + targetPort: http + protocol: TCP + name: http + selector: + app: canary-demo +--- +apiVersion: v1 +kind: Service +metadata: + name: canary-demo +spec: + ports: + - port: 80 + targetPort: http + protocol: TCP + name: http + selector: + app: canary-demo +--- +apiVersion: argoproj.io/v1alpha1 +kind: Rollout +metadata: + name: canary-demo +spec: + replicas: 5 + revisionHistoryLimit: 1 + selector: + matchLabels: + app: canary-demo + template: + metadata: + labels: + app: canary-demo + spec: + containers: + - name: canary-demo + image: argoproj/rollouts-demo:green + imagePullPolicy: Always + ports: + - name: http + containerPort: 8080 + protocol: TCP + resources: + requests: + memory: 32Mi + cpu: 5m + strategy: + canary: + canaryService: canary-demo-preview + steps: + - setWeight: 20 + - pause: {} + - setWeight: 40 + - pause: { duration: 10 } + - setWeight: 60 + - pause: { duration: 10 } + - setWeight: 80 + - pause: { duration: 10 } diff --git a/examples/vault-inject-example.yaml b/examples/vault-inject-example.yaml new file mode 100644 index 0000000..b2d94a3 --- /dev/null +++ b/examples/vault-inject-example.yaml @@ -0,0 +1,38 @@ +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: vault-inject-example +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: vault-inject-example-deployment +spec: + replicas: 1 + selector: + matchLabels: + app: vault-inject-example + template: + metadata: + labels: + app: vault-inject-example + annotations: + vault.hashicorp.com/agent-inject: "true" + vault.hashicorp.com/role: "vault-example" + vault.hashicorp.com/agent-inject-secret-env: "vault-example/creds" + vault.hashicorp.com/auth-path: "auth/kubernetes-local" + vault.hashicorp.com/agent-inject-template-env: | + {{- with secret "vault-example/creds" -}} + {{- range $key, $value := .Data.data }} + export {{ $key }}={{ $value }} + {{- end }} + {{- end }} + spec: + containers: + - name: app + image: "postgres:latest" + env: + - name: POSTGRES_PASSWORD + value: admin + serviceAccountName: vault-inject-example diff --git a/pkg/config/ansible_playbook_config.go b/internal/config/ansible_playbook_config.go similarity index 100% rename from pkg/config/ansible_playbook_config.go rename to internal/config/ansible_playbook_config.go diff --git a/pkg/config/config.go b/internal/config/config.go similarity index 100% rename from pkg/config/config.go rename to internal/config/config.go diff --git a/pkg/config/kubernetes.go b/internal/config/kubernetes.go similarity index 100% rename from pkg/config/kubernetes.go rename to internal/config/kubernetes.go diff --git a/pkg/config/modules_additional.go b/internal/config/modules_additional.go similarity index 100% rename from pkg/config/modules_additional.go rename to internal/config/modules_additional.go diff --git a/pkg/config/modules_cicd.go b/internal/config/modules_cicd.go similarity index 83% rename from pkg/config/modules_cicd.go rename to internal/config/modules_cicd.go index da28fce..42d9599 100644 --- a/pkg/config/modules_cicd.go +++ b/internal/config/modules_cicd.go @@ -37,5 +37,16 @@ type Cicd struct { ChartRef string `yaml:"chart_ref" env-default:"kube-forge/argo-rollouts"` ChartVersion string `yaml:"chart_version" env-default:"2.35.1"` Enabled bool `yaml:"enabled"` + Ha struct { + Enabled bool `yaml:"enabled"` + } `yaml:"ha"` + Expose struct { + Type string `yaml:"type"` + NodePort int `yaml:"node_port" env-default:"30010"` + } `yaml:"expose"` + Controller struct { + } `yaml:"controller"` + Dashboard struct { + } `yaml:"dashboard"` } `yaml:"rollouts"` } diff --git a/pkg/config/modules_observability.go b/internal/config/modules_observability.go similarity index 100% rename from pkg/config/modules_observability.go rename to internal/config/modules_observability.go diff --git a/pkg/config/modules_registry.go b/internal/config/modules_registry.go similarity index 100% rename from pkg/config/modules_registry.go rename to internal/config/modules_registry.go diff --git a/pkg/config/modules_secrets_storage.go b/internal/config/modules_secrets_storage.go similarity index 96% rename from pkg/config/modules_secrets_storage.go rename to internal/config/modules_secrets_storage.go index 8814916..e0d5ab2 100644 --- a/pkg/config/modules_secrets_storage.go +++ b/internal/config/modules_secrets_storage.go @@ -7,7 +7,7 @@ type SecretsStorage struct { KeyShares int `yaml:"key_shares" env-default:"5"` KeyThreshold int `yaml:"key_threshold" env-default:"3"` UnsealKeys []string `yaml:"unseal_keys" env-default:"[]"` - RootToken string + AuthToken string `yaml:"auth_token" env-default:""` Expose struct { Type string `yaml:"type"` Domain string `yaml:"domain"` diff --git a/pkg/config/orchestrator.go b/internal/config/orchestrator.go similarity index 100% rename from pkg/config/orchestrator.go rename to internal/config/orchestrator.go diff --git a/pkg/config/utility.go b/internal/config/utility.go similarity index 100% rename from pkg/config/utility.go rename to internal/config/utility.go diff --git a/internal/kubernetes_client/errors.go b/internal/kubernetes_client/errors.go new file mode 100644 index 0000000..d4cb191 --- /dev/null +++ b/internal/kubernetes_client/errors.go @@ -0,0 +1,5 @@ +package kubernetes_client + +import "errors" + +var NoSuchVarInPod = errors.New("No such variable in pod!") diff --git a/pkg/kubernetes_client/pod.go b/internal/kubernetes_client/pod.go similarity index 70% rename from pkg/kubernetes_client/pod.go rename to internal/kubernetes_client/pod.go index ea8e1b3..1e4d077 100644 --- a/pkg/kubernetes_client/pod.go +++ b/internal/kubernetes_client/pod.go @@ -4,7 +4,7 @@ import ( "bytes" "context" "fmt" - "kube-forge/pkg/config" + "kube-forge/internal/config" "net/http" "strings" "time" @@ -15,12 +15,11 @@ import ( "k8s.io/client-go/tools/remotecommand" ) -func ExecuteCommandInPodContainer(command string, namespace string, podName string, container string) (string, error) { +func ExecuteCommandInPodContainer(commandArray []string, namespace string, podName string, container string) (string, error) { clientset, err := kubernetes.NewForConfig(config.GetKubernetesConfig()) if err != nil { panic(err.Error()) } - commandArray := strings.Split(command, " ") execRequest := clientset.CoreV1().RESTClient().Post(). Resource("pods"). @@ -78,3 +77,25 @@ func GetPodByName(podName string, podNamespace string) (*corev1.Pod, error) { } return nil, err } + +func GetEnvVariableFromPodContainer(envVarName string, podNamespace string, podName string, containerName string) (string, error) { + commandArray := []string{"env"} + output, err := ExecuteCommandInPodContainer( + commandArray, podNamespace, podName, containerName, + ) + if err != nil { + return output, err + } + lines := strings.Split(output, "\n") + + for _, line := range lines { + if strings.HasPrefix(line, envVarName+"=") { + parts := strings.Split(line, "=") + if len(parts) == 2 { + value := parts[1] + return value, nil + } + } + } + return "", NoSuchVarInPod +} diff --git a/pkg/kubespray/cluster.go b/internal/kubespray/cluster.go similarity index 62% rename from pkg/kubespray/cluster.go rename to internal/kubespray/cluster.go index 06da4ec..ab828df 100644 --- a/pkg/kubespray/cluster.go +++ b/internal/kubespray/cluster.go @@ -1,17 +1,20 @@ package kubespray import ( - "kube-forge/pkg/config" - "kube-forge/pkg/secrets_storage" + "fmt" + "kube-forge/internal/config" + "kube-forge/internal/secrets_storage" ) func InstallCluster(tags string) { - runPlaybook("kubespray/project/cluster.yml", tags) + // runPlaybook("kubespray/project/cluster.yml", tags) config := config.GetConfig() if config.Modules.SecretsStorage.Enabled { + fmt.Println("## Additional Vault Configuration") secrets_storage.InitVault() secrets_storage.UnsealVault() + secrets_storage.AddKubernetesLocalIntegration() } } diff --git a/pkg/kubespray/utility.go b/internal/kubespray/utility.go similarity index 98% rename from pkg/kubespray/utility.go rename to internal/kubespray/utility.go index ba5ff28..327c82e 100644 --- a/pkg/kubespray/utility.go +++ b/internal/kubespray/utility.go @@ -3,7 +3,7 @@ package kubespray import ( "context" "io" - "kube-forge/pkg/config" + "kube-forge/internal/config" "os" "path/filepath" diff --git a/internal/registry/commands.go b/internal/registry/commands.go new file mode 100644 index 0000000..062c3ec --- /dev/null +++ b/internal/registry/commands.go @@ -0,0 +1,9 @@ +package registry + +func CreateDockerRepositories() { + +} + +func CreateHelmRepositories() { + +} diff --git a/internal/registry/errors.go b/internal/registry/errors.go new file mode 100644 index 0000000..e69de29 diff --git a/pkg/resources/resources.go b/internal/resources/resources.go similarity index 100% rename from pkg/resources/resources.go rename to internal/resources/resources.go diff --git a/pkg/resources/templates/helm-apps/releases/additional-modules/cert-manager.yml.tmpl b/internal/resources/templates/helm-apps/releases/additional-modules/cert-manager.yml.tmpl similarity index 100% rename from pkg/resources/templates/helm-apps/releases/additional-modules/cert-manager.yml.tmpl rename to internal/resources/templates/helm-apps/releases/additional-modules/cert-manager.yml.tmpl diff --git a/pkg/resources/templates/helm-apps/releases/additional-modules/docker-secrets-generator.yml.tmpl b/internal/resources/templates/helm-apps/releases/additional-modules/docker-secrets-generator.yml.tmpl similarity index 100% rename from pkg/resources/templates/helm-apps/releases/additional-modules/docker-secrets-generator.yml.tmpl rename to internal/resources/templates/helm-apps/releases/additional-modules/docker-secrets-generator.yml.tmpl diff --git a/pkg/resources/templates/helm-apps/releases/additional-modules/ingress-nginx.yml.tmpl b/internal/resources/templates/helm-apps/releases/additional-modules/ingress-nginx.yml.tmpl similarity index 100% rename from pkg/resources/templates/helm-apps/releases/additional-modules/ingress-nginx.yml.tmpl rename to internal/resources/templates/helm-apps/releases/additional-modules/ingress-nginx.yml.tmpl diff --git a/pkg/resources/templates/helm-apps/releases/additional-modules/longhorn.yml.tmpl b/internal/resources/templates/helm-apps/releases/additional-modules/longhorn.yml.tmpl similarity index 100% rename from pkg/resources/templates/helm-apps/releases/additional-modules/longhorn.yml.tmpl rename to internal/resources/templates/helm-apps/releases/additional-modules/longhorn.yml.tmpl diff --git a/pkg/resources/templates/helm-apps/releases/additional-modules/secrets-store-csi-driver.yml.tmpl b/internal/resources/templates/helm-apps/releases/additional-modules/secrets-store-csi-driver.yml.tmpl similarity index 100% rename from pkg/resources/templates/helm-apps/releases/additional-modules/secrets-store-csi-driver.yml.tmpl rename to internal/resources/templates/helm-apps/releases/additional-modules/secrets-store-csi-driver.yml.tmpl diff --git a/pkg/resources/templates/helm-apps/releases/cicd/argo-cd-ingress.yml.tmpl b/internal/resources/templates/helm-apps/releases/cicd/argo-cd-ingress.yml.tmpl similarity index 100% rename from pkg/resources/templates/helm-apps/releases/cicd/argo-cd-ingress.yml.tmpl rename to internal/resources/templates/helm-apps/releases/cicd/argo-cd-ingress.yml.tmpl diff --git a/pkg/resources/templates/helm-apps/releases/cicd/argo-cd.yml.tmpl b/internal/resources/templates/helm-apps/releases/cicd/argo-cd.yml.tmpl similarity index 100% rename from pkg/resources/templates/helm-apps/releases/cicd/argo-cd.yml.tmpl rename to internal/resources/templates/helm-apps/releases/cicd/argo-cd.yml.tmpl diff --git a/pkg/resources/templates/helm-apps/releases/cicd/argo-rollouts.yml.tmpl b/internal/resources/templates/helm-apps/releases/cicd/argo-rollouts.yml.tmpl similarity index 97% rename from pkg/resources/templates/helm-apps/releases/cicd/argo-rollouts.yml.tmpl rename to internal/resources/templates/helm-apps/releases/cicd/argo-rollouts.yml.tmpl index 1cf16c1..0d51168 100644 --- a/pkg/resources/templates/helm-apps/releases/cicd/argo-rollouts.yml.tmpl +++ b/internal/resources/templates/helm-apps/releases/cicd/argo-rollouts.yml.tmpl @@ -70,7 +70,11 @@ # -- [priorityClassName] for the controller priorityClassName: "" # -- The number of controller pods to run - replicas: 2 + {{- if .Modules.Cicd.Rollouts.Ha.Enabled }} + replicas: 3 + {{- else }} + replicas: 1 + {{- end }} image: # -- Registry to use registry: quay.io @@ -280,7 +284,11 @@ createClusterRole: true # -- The number of dashboard pods to run + {{- if .Modules.Cicd.Rollouts.Ha.Enabled }} + replicas: 3 + {{- else }} replicas: 1 + {{- end }} image: # -- Registry to use registry: quay.io @@ -305,7 +313,13 @@ containerSecurityContext: {} service: # -- Sets the type of the Service + {{- if eq .Modules.Cicd.Rollouts.Expose.Type "NodePort" }} + type: NodePort + nodePort: {{ .Modules.Cicd.Rollouts.Expose.NodePort }} + {{- else }} type: ClusterIP + nodePort: + {{- end }} # -- LoadBalancer will get created with the IP specified in this field loadBalancerIP: "" # -- Source IP ranges to allow access to service from @@ -323,7 +337,7 @@ # -- Service target port targetPort: 3100 # -- (int) Service nodePort - nodePort: + serviceAccount: # -- Specifies whether a dashboard service account should be created create: true diff --git a/internal/resources/templates/helm-apps/releases/cicd/keel.yml.tmpl b/internal/resources/templates/helm-apps/releases/cicd/keel.yml.tmpl new file mode 100644 index 0000000..aef046b --- /dev/null +++ b/internal/resources/templates/helm-apps/releases/cicd/keel.yml.tmpl @@ -0,0 +1,255 @@ +- name: keel + namespace: kube-system + chart_ref: {{ .Modules.Cicd.UpdatesOperator.ChartRef }} + chart_version: {{ .Modules.Cicd.UpdatesOperator.ChartVersion }} + {{- if and .Modules.Cicd.Enabled .Modules.Cicd.UpdatesOperator.Enabled }} + release_state: "present" + {{- else }} + release_state: "absent" + {{- end }} + values: + image: + repository: keelhq/keel + tag: null + pullPolicy: Always + + # Enable insecure registries + insecureRegistry: false + + # Polling is enabled by default, + # you can disable it setting value below to false + polling: + enabled: true + defaultSchedule: "@every 1m" + + # Extra Containers to run alongside Keel + # extraContainers: + # - name: busybox + # image: busybox + # imagePullPolicy: IfNotPresent + # command: ['sh', '-c', 'echo Container 1 is Running ; sleep 3600'] + + # Helm provider support + helmProvider: + enabled: true + # set to version "v3" for Helm v3 + version: "v2" + tillerNamespace: "kube-system" + # optional Tiller address (if portforwarder tunnel doesn't work), + # if you are using default configuration, setting it to + # 'tiller-deploy:44134' is usually fine + tillerAddress: 'tiller-deploy:44134' + # helmDriver: '' + # helmDriverSqlConnectionString: '' + + # Google Container Registry + # GCP Project ID + gcr: + enabled: false + projectId: "" + gcpServiceAccount: "" + clusterName: "" + pubSub: + enabled: false + + # Notification level (debug, info, success, warn, error, fatal) + notificationLevel: info + + # AWS Elastic Container Registry + # https://keel.sh/v1/guide/documentation.html#Polling-with-AWS-ECR + ecr: + enabled: false + roleArn: "" + accessKeyId: "" + secretAccessKey: "" + region: "" + + # Webhook Notification + # Remote webhook endpoint for notification delivery + webhook: + enabled: false + endpoint: "" + + # Slack Notification + # bot name (default keel) must exist! + slack: + enabled: false + botName: "" + token: "" + channel: "" + approvalsChannel: "" + + # Hipchat notification and approvals + hipchat: + enabled: false + token: "" + channel: "" + approvalsChannel: "" + botName: "" + userName: "" + password: "" + + # Mattermost notifications + mattermost: + enabled: false + endpoint: "" + + # MS Teams notifications + teams: + enabled: false + webhookUrl: "" + + # Discord notifications + discord: + enabled: false + webhookUrl: "" + + # Mail notifications + mail: + enabled: false + from: "" + to: "" + smtp: + server: "" + port: 25 + user: "" + pass: "" + + # Basic auth on approvals + basicauth: + enabled: true + user: "admin" + password: "{{ .Modules.AdminPassword }}" + + # Keel service + # Enable to receive webhooks from Docker registries + service: + enabled: false + type: LoadBalancer + externalPort: 9300 + clusterIP: "" + + # Webhook Relay service + # If you don’t want to expose your Keel service, you can use https://webhookrelay.com/ + # which can deliver webhooks to your internal Keel service through Keel sidecar container. + webhookRelay: + enabled: false + bucket: "" + # webhookrelay.com credentials + # Set the key and secret values here to create the keel-webhookrelay secret with this + # chart -or- leave key and secret blank and create the keel-webhookrelay secret separately. + key: "" + secret: "" + # webhookrelay docker image + image: + repository: webhookrelay/webhookrelayd + tag: latest + pullPolicy: IfNotPresent + + # Use a secret file to define passwords and tokens of third parties. + secret: + # Leave blank to use `keel.fullname` + name: "" + # Set to false to manage your own secret file, with terraform for example. + create: true + + # Keel self-update + # uncomment lines below if you want Keel to automaticly + # self-update to the latest release version + # keel: + # # keel policy (all/major/minor/patch/force) + # policy: patch + # # trigger type, defaults to events such as pubsub, webhooks + # trigger: poll + # # polling schedule + # pollSchedule: "@every 3m" + # # images to track and update + # images: + # - repository: image.repository + # tag: image.tag + + # RBAC manifests management + rbac: + enabled: true + serviceAccount: + # Kubernetes service account name to be used for ClusterRoleBinding and Deployment. + # name: + # Create a new Kubernetes service account automatically. Set to false if you want to use your own service account. + # If rbac.serviceAccount.name is not set, a new name for the service account is generated + create: true + + # Resources + resources: + limits: + cpu: 100m + memory: 128Mi + requests: + cpu: 50m + memory: 64Mi + + # NodeSelector + nodeSelector: {} + + affinity: {} + + tolerations: {} + + # base64 encoded json of GCP service account + # more info available here: https://cloud.google.com/kubernetes-engine/docs/tutorials/authenticating-to-cloud-platform + # e.g. --set googleApplicationCredentials=$(cat | base64) + googleApplicationCredentials: "" + + # Enable DEBUG logging + debug: false + + # This is used by the static manifest generator in order to create a static + # namespace manifest for the namespace that keel is being installed + # within. It should **not** be used if you are using Helm for deployment. + createNamespaceResource: false + + podAnnotations: {} + + serviceAnnotations: {} + # Useful for making the load balancer internal + # serviceAnnotations: + # cloud.google.com/load-balancer-type: Internal + + aws: + region: null + + podDisruptionBudget: + enabled: false + maxUnavailable: 1 + minAvailable: null + + # Google Cloud Certificates + gcloud: + managedCertificates: + enabled: false + domains: + - "" + + ingress: + enabled: false + labels: {} + annotations: {} + # kubernetes.io/ingress.class: nginx + # kubernetes.io/tls-acme: "true" + hosts: [] + # - host: chart-example.local + # paths: + # - / + tls: [] + # - secretName: chart-example-tls + # hosts: + # - chart-example.local + + dockerRegistry: + enabled: false + name: "" + key: "" + + persistence: + enabled: false + storageClass: "-" + size: 1Gi diff --git a/pkg/resources/templates/helm-apps/releases/observability/fluent-operator.yml.tmpl b/internal/resources/templates/helm-apps/releases/observability/fluent-operator.yml.tmpl similarity index 100% rename from pkg/resources/templates/helm-apps/releases/observability/fluent-operator.yml.tmpl rename to internal/resources/templates/helm-apps/releases/observability/fluent-operator.yml.tmpl diff --git a/pkg/resources/templates/helm-apps/releases/observability/loki.yml.tmpl b/internal/resources/templates/helm-apps/releases/observability/loki.yml.tmpl similarity index 100% rename from pkg/resources/templates/helm-apps/releases/observability/loki.yml.tmpl rename to internal/resources/templates/helm-apps/releases/observability/loki.yml.tmpl diff --git a/pkg/resources/templates/helm-apps/releases/observability/observability.yml.tmpl b/internal/resources/templates/helm-apps/releases/observability/observability.yml.tmpl similarity index 100% rename from pkg/resources/templates/helm-apps/releases/observability/observability.yml.tmpl rename to internal/resources/templates/helm-apps/releases/observability/observability.yml.tmpl diff --git a/pkg/resources/templates/helm-apps/releases/observability/opentelemetry-operator.yml.tmpl b/internal/resources/templates/helm-apps/releases/observability/opentelemetry-operator.yml.tmpl similarity index 100% rename from pkg/resources/templates/helm-apps/releases/observability/opentelemetry-operator.yml.tmpl rename to internal/resources/templates/helm-apps/releases/observability/opentelemetry-operator.yml.tmpl diff --git a/pkg/resources/templates/helm-apps/releases/observability/tempo.yml.tmpl b/internal/resources/templates/helm-apps/releases/observability/tempo.yml.tmpl similarity index 100% rename from pkg/resources/templates/helm-apps/releases/observability/tempo.yml.tmpl rename to internal/resources/templates/helm-apps/releases/observability/tempo.yml.tmpl diff --git a/pkg/resources/templates/helm-apps/releases/registry/harbor-certificate-generator.yml.tmpl b/internal/resources/templates/helm-apps/releases/registry/harbor-certificate-generator.yml.tmpl similarity index 100% rename from pkg/resources/templates/helm-apps/releases/registry/harbor-certificate-generator.yml.tmpl rename to internal/resources/templates/helm-apps/releases/registry/harbor-certificate-generator.yml.tmpl diff --git a/pkg/resources/templates/helm-apps/releases/registry/harbor.yml.tmpl b/internal/resources/templates/helm-apps/releases/registry/harbor.yml.tmpl similarity index 99% rename from pkg/resources/templates/helm-apps/releases/registry/harbor.yml.tmpl rename to internal/resources/templates/helm-apps/releases/registry/harbor.yml.tmpl index 63a8830..dbecedf 100644 --- a/pkg/resources/templates/helm-apps/releases/registry/harbor.yml.tmpl +++ b/internal/resources/templates/helm-apps/releases/registry/harbor.yml.tmpl @@ -134,7 +134,7 @@ portal: image: - repository: goharbor/harbor-portal + repository: harbor.kvazaric.ru/kube-forge/harbor-portal tag: {{ .Modules.Registry.Version }} serviceAccountName: "" automountServiceAccountToken: false diff --git a/pkg/resources/templates/helm-apps/releases/secrets-storage/vault.yml.tmpl b/internal/resources/templates/helm-apps/releases/secrets-storage/vault.yml.tmpl similarity index 100% rename from pkg/resources/templates/helm-apps/releases/secrets-storage/vault.yml.tmpl rename to internal/resources/templates/helm-apps/releases/secrets-storage/vault.yml.tmpl diff --git a/pkg/resources/templates/helm-apps/repositories/repositories.yml.tmpl b/internal/resources/templates/helm-apps/repositories/repositories.yml.tmpl similarity index 100% rename from pkg/resources/templates/helm-apps/repositories/repositories.yml.tmpl rename to internal/resources/templates/helm-apps/repositories/repositories.yml.tmpl diff --git a/pkg/resources/templates/kubespray/inventory/group_vars/all.yml.tmpl b/internal/resources/templates/kubespray/inventory/group_vars/all.yml.tmpl similarity index 100% rename from pkg/resources/templates/kubespray/inventory/group_vars/all.yml.tmpl rename to internal/resources/templates/kubespray/inventory/group_vars/all.yml.tmpl diff --git a/pkg/resources/templates/kubespray/inventory/group_vars/k8s_cluster/addons.yml.tmpl b/internal/resources/templates/kubespray/inventory/group_vars/k8s_cluster/addons.yml.tmpl similarity index 100% rename from pkg/resources/templates/kubespray/inventory/group_vars/k8s_cluster/addons.yml.tmpl rename to internal/resources/templates/kubespray/inventory/group_vars/k8s_cluster/addons.yml.tmpl diff --git a/pkg/resources/templates/kubespray/inventory/group_vars/k8s_cluster/k8s-cluster.yml.tmpl b/internal/resources/templates/kubespray/inventory/group_vars/k8s_cluster/k8s-cluster.yml.tmpl similarity index 100% rename from pkg/resources/templates/kubespray/inventory/group_vars/k8s_cluster/k8s-cluster.yml.tmpl rename to internal/resources/templates/kubespray/inventory/group_vars/k8s_cluster/k8s-cluster.yml.tmpl diff --git a/pkg/resources/templates/kubespray/inventory/hosts.tmpl b/internal/resources/templates/kubespray/inventory/hosts.tmpl similarity index 100% rename from pkg/resources/templates/kubespray/inventory/hosts.tmpl rename to internal/resources/templates/kubespray/inventory/hosts.tmpl diff --git a/pkg/resources/templates/secrets-storage/vault-keys.json.tmpl b/internal/resources/templates/secrets-storage/vault-keys.json.tmpl similarity index 67% rename from pkg/resources/templates/secrets-storage/vault-keys.json.tmpl rename to internal/resources/templates/secrets-storage/vault-keys.json.tmpl index c52153f..a326df1 100644 --- a/pkg/resources/templates/secrets-storage/vault-keys.json.tmpl +++ b/internal/resources/templates/secrets-storage/vault-keys.json.tmpl @@ -4,5 +4,5 @@ "{{ $key }}", {{- end }} ], - "root_token": "{{ .Modules.SecretsStorage.RootToken }}" + "root_token": "{{ .Modules.SecretsStorage.AuthToken }}" } \ No newline at end of file diff --git a/internal/secrets_storage/commands.go b/internal/secrets_storage/commands.go new file mode 100644 index 0000000..12ceb0d --- /dev/null +++ b/internal/secrets_storage/commands.go @@ -0,0 +1,129 @@ +package secrets_storage + +import ( + "fmt" + "kube-forge/internal/config" + "kube-forge/internal/kubernetes_client" + "kube-forge/internal/templates" + "regexp" + "strings" +) + +func InitVault() { + _, err := kubernetes_client.GetPodByName("vault-0", "secrets-storage") + if err != nil { + fmt.Println(err.Error()) + return + } + err = commandToInitVault() + if err != nil { + fmt.Println(err.Error()) + return + } + fmt.Println("Vault initialized") + templates.ApplyVaultInitKeysTemplate() +} + +func AddKubernetesLocalIntegration() { + _, err := kubernetes_client.GetPodByName("vault-0", "secrets-storage") + if err != nil { + fmt.Println(err.Error()) + return + } + err = commandToAddKubernetesLocalIntegration() + if err != nil { + fmt.Println(err.Error()) + return + } + fmt.Println("Vault local Kubernetes integration added") +} + +func UnsealVault() { + _, err := kubernetes_client.GetPodByName("vault-0", "secrets-storage") + if err != nil { + fmt.Println(err.Error()) + return + } + commandToUnsealVault() +} + +func commandToInitVault() error { + config := config.GetConfig() + commandArray := []string{ + "vault", "operator", "init", + fmt.Sprintf("-key-shares=%d", config.Modules.SecretsStorage.KeyShares), + fmt.Sprintf("-key-threshold=%d", config.Modules.SecretsStorage.KeyThreshold), + } + output, err := kubernetes_client.ExecuteCommandInPodContainer( + commandArray, "secrets-storage", "vault-0", "vault", + ) + if err != nil && strings.Contains(output, "Vault is already initialized") { + return VaultAlreadyInitialised + } + + unsealKeys, rootToken := parseVaultInitKeys(output) + config.Modules.SecretsStorage.UnsealKeys = unsealKeys + config.Modules.SecretsStorage.AuthToken = rootToken + return nil +} + +func parseVaultInitKeys(input string) ([]string, string) { + unsealKeyPattern := regexp.MustCompile(`Unseal Key \d+: (\S+)`) + rootTokenPattern := regexp.MustCompile(`Initial Root Token: (\S+)`) + + unsealKeysMatches := unsealKeyPattern.FindAllStringSubmatch(input, -1) + var unsealKeys []string + for _, match := range unsealKeysMatches { + unsealKeys = append(unsealKeys, match[1]) + } + + rootTokenMatches := rootTokenPattern.FindStringSubmatch(input) + rootToken := rootTokenMatches[1] + + return unsealKeys, rootToken +} + +func commandToUnsealVault() { + config := config.GetConfig() + + for _, unsealKey := range config.Modules.SecretsStorage.UnsealKeys { + commandArray := []string{"vault", "operator", "unseal", unsealKey} + kubernetes_client.ExecuteCommandInPodContainer( + commandArray, "secrets-storage", "vault-0", "vault", + ) + } + fmt.Println("Vault unsealed") +} + +func commandToAddKubernetesLocalIntegration() error { + config := config.GetConfig() + + commandArray := []string{"vault", "login", config.Modules.SecretsStorage.AuthToken} + output, err := kubernetes_client.ExecuteCommandInPodContainer( + commandArray, "secrets-storage", "vault-0", "vault", + ) + if err != nil && strings.Contains(output, "permission denied") { + return IncorrectCredentials + } + commandArray = []string{"vault", "auth", "enable", "-local", "-path=kubernetes-local", "kubernetes"} + output, err = kubernetes_client.ExecuteCommandInPodContainer( + commandArray, "secrets-storage", "vault-0", "vault", + ) + kubernetesInternalServiceAddr, err := kubernetes_client.GetEnvVariableFromPodContainer( + "KUBERNETES_PORT_443_TCP_ADDR", + "secrets-storage", + "vault-0", + "vault", + ) + if err != nil { + return err + } + commandArray = []string{ + "vault", "write", "auth/kubernetes-local/config", + fmt.Sprintf("kubernetes_host=https://%s:443", kubernetesInternalServiceAddr), + } + output, err = kubernetes_client.ExecuteCommandInPodContainer( + commandArray, "secrets-storage", "vault-0", "vault", + ) + return nil +} diff --git a/pkg/secrets_storage/errors.go b/internal/secrets_storage/errors.go similarity index 57% rename from pkg/secrets_storage/errors.go rename to internal/secrets_storage/errors.go index 4a92e37..ed395b8 100644 --- a/pkg/secrets_storage/errors.go +++ b/internal/secrets_storage/errors.go @@ -3,3 +3,4 @@ package secrets_storage import "errors" var VaultAlreadyInitialised = errors.New("Vault already initialised") +var IncorrectCredentials = errors.New("Incorrect Vault auth token credentials!!") diff --git a/pkg/templates/funcs.go b/internal/templates/funcs.go similarity index 100% rename from pkg/templates/funcs.go rename to internal/templates/funcs.go diff --git a/pkg/templates/helm_apps.go b/internal/templates/helm_apps.go similarity index 97% rename from pkg/templates/helm_apps.go rename to internal/templates/helm_apps.go index f142002..cf90c4c 100644 --- a/pkg/templates/helm_apps.go +++ b/internal/templates/helm_apps.go @@ -1,8 +1,8 @@ package templates import ( - "kube-forge/pkg/config" - "kube-forge/pkg/resources" + "kube-forge/internal/config" + "kube-forge/internal/resources" "strings" ) diff --git a/pkg/templates/kubespray.go b/internal/templates/kubespray.go similarity index 100% rename from pkg/templates/kubespray.go rename to internal/templates/kubespray.go diff --git a/pkg/templates/secrets_storage.go b/internal/templates/secrets_storage.go similarity index 91% rename from pkg/templates/secrets_storage.go rename to internal/templates/secrets_storage.go index a972d40..149d5eb 100644 --- a/pkg/templates/secrets_storage.go +++ b/internal/templates/secrets_storage.go @@ -2,7 +2,7 @@ package templates import ( "fmt" - "kube-forge/pkg/config" + "kube-forge/internal/config" ) func ApplyVaultInitKeysTemplate() { diff --git a/pkg/templates/utility.go b/internal/templates/utility.go similarity index 94% rename from pkg/templates/utility.go rename to internal/templates/utility.go index e40e713..305169b 100644 --- a/pkg/templates/utility.go +++ b/internal/templates/utility.go @@ -3,8 +3,8 @@ package templates import ( "bytes" "embed" - "kube-forge/pkg/config" - "kube-forge/pkg/resources" + "kube-forge/internal/config" + "kube-forge/internal/resources" "os" "path/filepath" "text/template" diff --git a/kubespray/inventory/group_vars/k8s_cluster/addons.yml b/kubespray/inventory/group_vars/k8s_cluster/addons.yml index b656a69..3a1ee8b 100644 --- a/kubespray/inventory/group_vars/k8s_cluster/addons.yml +++ b/kubespray/inventory/group_vars/k8s_cluster/addons.yml @@ -3903,7 +3903,7 @@ releases: portal: image: - repository: goharbor/harbor-portal + repository: harbor.kvazaric.ru/kube-forge/harbor-portal tag: v2.10.1 serviceAccountName: "" automountServiceAccountToken: false @@ -4213,7 +4213,7 @@ releases: server.insecure: true secret: - argocdServerAdminPassword: $2a$10$7M.OEGsyvWrf.T4j1R.dK.BuIl75k8JzbSthgl8mCvrhec05Q.ICe + argocdServerAdminPassword: $2a$10$VHPmJIIKxsrAkLeAyNGDNOdlJAijATxjKeem29j6X4MN8zLYPMipi repositories: # add default helm-repository from harbor @@ -4330,7 +4330,7 @@ releases: # -- [priorityClassName] for the controller priorityClassName: "" # -- The number of controller pods to run - replicas: 2 + replicas: 1 image: # -- Registry to use registry: quay.io @@ -4564,6 +4564,7 @@ releases: service: # -- Sets the type of the Service type: ClusterIP + nodePort: # -- LoadBalancer will get created with the IP specified in this field loadBalancerIP: "" # -- Source IP ranges to allow access to service from @@ -4581,7 +4582,7 @@ releases: # -- Service target port targetPort: 3100 # -- (int) Service nodePort - nodePort: + serviceAccount: # -- Specifies whether a dashboard service account should be created create: true @@ -4683,6 +4684,252 @@ releases: chart_ref: kube-forge/keel chart_version: 1.0.3 release_state: "present" + values: + image: + repository: keelhq/keel + tag: null + pullPolicy: Always + + # Enable insecure registries + insecureRegistry: false + + # Polling is enabled by default, + # you can disable it setting value below to false + polling: + enabled: true + defaultSchedule: "@every 1m" + + # Extra Containers to run alongside Keel + # extraContainers: + # - name: busybox + # image: busybox + # imagePullPolicy: IfNotPresent + # command: ['sh', '-c', 'echo Container 1 is Running ; sleep 3600'] + + # Helm provider support + helmProvider: + enabled: true + # set to version "v3" for Helm v3 + version: "v2" + tillerNamespace: "kube-system" + # optional Tiller address (if portforwarder tunnel doesn't work), + # if you are using default configuration, setting it to + # 'tiller-deploy:44134' is usually fine + tillerAddress: 'tiller-deploy:44134' + # helmDriver: '' + # helmDriverSqlConnectionString: '' + + # Google Container Registry + # GCP Project ID + gcr: + enabled: false + projectId: "" + gcpServiceAccount: "" + clusterName: "" + pubSub: + enabled: false + + # Notification level (debug, info, success, warn, error, fatal) + notificationLevel: info + + # AWS Elastic Container Registry + # https://keel.sh/v1/guide/documentation.html#Polling-with-AWS-ECR + ecr: + enabled: false + roleArn: "" + accessKeyId: "" + secretAccessKey: "" + region: "" + + # Webhook Notification + # Remote webhook endpoint for notification delivery + webhook: + enabled: false + endpoint: "" + + # Slack Notification + # bot name (default keel) must exist! + slack: + enabled: false + botName: "" + token: "" + channel: "" + approvalsChannel: "" + + # Hipchat notification and approvals + hipchat: + enabled: false + token: "" + channel: "" + approvalsChannel: "" + botName: "" + userName: "" + password: "" + + # Mattermost notifications + mattermost: + enabled: false + endpoint: "" + + # MS Teams notifications + teams: + enabled: false + webhookUrl: "" + + # Discord notifications + discord: + enabled: false + webhookUrl: "" + + # Mail notifications + mail: + enabled: false + from: "" + to: "" + smtp: + server: "" + port: 25 + user: "" + pass: "" + + # Basic auth on approvals + basicauth: + enabled: true + user: "admin" + password: "changeit" + + # Keel service + # Enable to receive webhooks from Docker registries + service: + enabled: false + type: LoadBalancer + externalPort: 9300 + clusterIP: "" + + # Webhook Relay service + # If you don’t want to expose your Keel service, you can use https://webhookrelay.com/ + # which can deliver webhooks to your internal Keel service through Keel sidecar container. + webhookRelay: + enabled: false + bucket: "" + # webhookrelay.com credentials + # Set the key and secret values here to create the keel-webhookrelay secret with this + # chart -or- leave key and secret blank and create the keel-webhookrelay secret separately. + key: "" + secret: "" + # webhookrelay docker image + image: + repository: webhookrelay/webhookrelayd + tag: latest + pullPolicy: IfNotPresent + + # Use a secret file to define passwords and tokens of third parties. + secret: + # Leave blank to use `keel.fullname` + name: "" + # Set to false to manage your own secret file, with terraform for example. + create: true + + # Keel self-update + # uncomment lines below if you want Keel to automaticly + # self-update to the latest release version + # keel: + # # keel policy (all/major/minor/patch/force) + # policy: patch + # # trigger type, defaults to events such as pubsub, webhooks + # trigger: poll + # # polling schedule + # pollSchedule: "@every 3m" + # # images to track and update + # images: + # - repository: image.repository + # tag: image.tag + + # RBAC manifests management + rbac: + enabled: true + serviceAccount: + # Kubernetes service account name to be used for ClusterRoleBinding and Deployment. + # name: + # Create a new Kubernetes service account automatically. Set to false if you want to use your own service account. + # If rbac.serviceAccount.name is not set, a new name for the service account is generated + create: true + + # Resources + resources: + limits: + cpu: 100m + memory: 128Mi + requests: + cpu: 50m + memory: 64Mi + + # NodeSelector + nodeSelector: {} + + affinity: {} + + tolerations: {} + + # base64 encoded json of GCP service account + # more info available here: https://cloud.google.com/kubernetes-engine/docs/tutorials/authenticating-to-cloud-platform + # e.g. --set googleApplicationCredentials=$(cat | base64) + googleApplicationCredentials: "" + + # Enable DEBUG logging + debug: false + + # This is used by the static manifest generator in order to create a static + # namespace manifest for the namespace that keel is being installed + # within. It should **not** be used if you are using Helm for deployment. + createNamespaceResource: false + + podAnnotations: {} + + serviceAnnotations: {} + # Useful for making the load balancer internal + # serviceAnnotations: + # cloud.google.com/load-balancer-type: Internal + + aws: + region: null + + podDisruptionBudget: + enabled: false + maxUnavailable: 1 + minAvailable: null + + # Google Cloud Certificates + gcloud: + managedCertificates: + enabled: false + domains: + - "" + + ingress: + enabled: false + labels: {} + annotations: {} + # kubernetes.io/ingress.class: nginx + # kubernetes.io/tls-acme: "true" + hosts: [] + # - host: chart-example.local + # paths: + # - / + tls: [] + # - secretName: chart-example-tls + # hosts: + # - chart-example.local + + dockerRegistry: + enabled: false + name: "" + key: "" + + persistence: + enabled: false + storageClass: "-" + size: 1Gi - name: argo-cd-ingress namespace: cicd diff --git a/pkg/resources/templates/helm-apps/releases/cicd/keel.yml.tmpl b/pkg/resources/templates/helm-apps/releases/cicd/keel.yml.tmpl deleted file mode 100644 index 0687947..0000000 --- a/pkg/resources/templates/helm-apps/releases/cicd/keel.yml.tmpl +++ /dev/null @@ -1,9 +0,0 @@ -- name: keel - namespace: kube-system - chart_ref: {{ .Modules.Cicd.UpdatesOperator.ChartRef }} - chart_version: {{ .Modules.Cicd.UpdatesOperator.ChartVersion }} - {{- if and .Modules.Cicd.Enabled .Modules.Cicd.UpdatesOperator.Enabled }} - release_state: "present" - {{- else }} - release_state: "absent" - {{- end }} diff --git a/pkg/secrets_storage/commands.go b/pkg/secrets_storage/commands.go deleted file mode 100644 index 0fc6b14..0000000 --- a/pkg/secrets_storage/commands.go +++ /dev/null @@ -1,98 +0,0 @@ -package secrets_storage - -import ( - "fmt" - "kube-forge/pkg/config" - "kube-forge/pkg/kubernetes_client" - "kube-forge/pkg/templates" - "regexp" - "strings" -) - -func InitVault() { - _, err := kubernetes_client.GetPodByName("vault-0", "secrets-storage") - if err != nil { - fmt.Println(err.Error()) - return - } - err = commandToInitVault() - if err != nil { - fmt.Println(err.Error()) - return - } - fmt.Println("Vault initialized") - templates.ApplyVaultInitKeysTemplate() -} - -func UnsealVault() { - _, err := kubernetes_client.GetPodByName("vault-0", "secrets-storage") - if err != nil { - fmt.Println(err.Error()) - return - } - commandToUnsealVault() -} - -// func getRunningVault(ctx context.Context, podName string, podNamespace string, responseChan chan<- error) { -// time.Sleep(1 * time.Minute) -// _, err := kubernetes_client.GetPodByName(ctx, podName, podNamespace) -// if err != nil { -// responseChan <- err -// } - -// commandToUnsealVault() -// responseChan <- nil -// close(responseChan) -// } - -func commandToInitVault() error { - config := config.GetConfig() - - command := fmt.Sprintf( - "vault operator init -key-shares=%d -key-threshold=%d", - config.Modules.SecretsStorage.KeyShares, - config.Modules.SecretsStorage.KeyThreshold, - ) - output, err := kubernetes_client.ExecuteCommandInPodContainer( - command, "secrets-storage", "vault-0", "vault", - ) - if err != nil && strings.Contains(output, "Vault is already initialized") { - return VaultAlreadyInitialised - } - - unsealKeys, rootToken := parseVaultInitKeys(output) - config.Modules.SecretsStorage.UnsealKeys = unsealKeys - config.Modules.SecretsStorage.RootToken = rootToken - return nil -} - -func parseVaultInitKeys(input string) ([]string, string) { - unsealKeyPattern := regexp.MustCompile(`Unseal Key \d+: (\S+)`) - rootTokenPattern := regexp.MustCompile(`Initial Root Token: (\S+)`) - - unsealKeysMatches := unsealKeyPattern.FindAllStringSubmatch(input, -1) - var unsealKeys []string - for _, match := range unsealKeysMatches { - unsealKeys = append(unsealKeys, match[1]) - } - - rootTokenMatches := rootTokenPattern.FindStringSubmatch(input) - rootToken := rootTokenMatches[1] - - return unsealKeys, rootToken -} - -func commandToUnsealVault() { - config := config.GetConfig() - - for _, unsealKey := range config.Modules.SecretsStorage.UnsealKeys { - command := fmt.Sprintf( - "vault operator unseal %s", - unsealKey, - ) - kubernetes_client.ExecuteCommandInPodContainer( - command, "secrets-storage", "vault-0", "vault", - ) - } - fmt.Println("Vault unsealed") -}