update vault integration
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -4,4 +4,4 @@
|
||||
*artifacts*
|
||||
*k8s-admin*
|
||||
vault-keys.json
|
||||
*config.yaml*
|
||||
config.yaml
|
||||
@@ -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"
|
||||
)
|
||||
|
||||
|
||||
@@ -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:
|
||||
|
||||
65
examples/rollouts-app-test.yaml
Normal file
65
examples/rollouts-app-test.yaml
Normal file
@@ -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 }
|
||||
38
examples/vault-inject-example.yaml
Normal file
38
examples/vault-inject-example.yaml
Normal file
@@ -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
|
||||
@@ -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"`
|
||||
}
|
||||
@@ -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"`
|
||||
5
internal/kubernetes_client/errors.go
Normal file
5
internal/kubernetes_client/errors.go
Normal file
@@ -0,0 +1,5 @@
|
||||
package kubernetes_client
|
||||
|
||||
import "errors"
|
||||
|
||||
var NoSuchVarInPod = errors.New("No such variable in pod!")
|
||||
@@ -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
|
||||
}
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ package kubespray
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"kube-forge/pkg/config"
|
||||
"kube-forge/internal/config"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
9
internal/registry/commands.go
Normal file
9
internal/registry/commands.go
Normal file
@@ -0,0 +1,9 @@
|
||||
package registry
|
||||
|
||||
func CreateDockerRepositories() {
|
||||
|
||||
}
|
||||
|
||||
func CreateHelmRepositories() {
|
||||
|
||||
}
|
||||
0
internal/registry/errors.go
Normal file
0
internal/registry/errors.go
Normal file
@@ -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
|
||||
@@ -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 <JSON_KEY_FIEL> | 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
|
||||
@@ -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
|
||||
@@ -4,5 +4,5 @@
|
||||
"{{ $key }}",
|
||||
{{- end }}
|
||||
],
|
||||
"root_token": "{{ .Modules.SecretsStorage.RootToken }}"
|
||||
"root_token": "{{ .Modules.SecretsStorage.AuthToken }}"
|
||||
}
|
||||
129
internal/secrets_storage/commands.go
Normal file
129
internal/secrets_storage/commands.go
Normal file
@@ -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
|
||||
}
|
||||
@@ -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!!")
|
||||
@@ -1,8 +1,8 @@
|
||||
package templates
|
||||
|
||||
import (
|
||||
"kube-forge/pkg/config"
|
||||
"kube-forge/pkg/resources"
|
||||
"kube-forge/internal/config"
|
||||
"kube-forge/internal/resources"
|
||||
"strings"
|
||||
)
|
||||
|
||||
@@ -2,7 +2,7 @@ package templates
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"kube-forge/pkg/config"
|
||||
"kube-forge/internal/config"
|
||||
)
|
||||
|
||||
func ApplyVaultInitKeysTemplate() {
|
||||
@@ -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"
|
||||
@@ -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 <JSON_KEY_FIEL> | 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
|
||||
|
||||
@@ -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 }}
|
||||
@@ -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")
|
||||
}
|
||||
Reference in New Issue
Block a user