diff --git a/apps/dns-resolver-pressure-test/dns-resolver-pressure-test b/apps/dns-resolver-pressure-test/dns-resolver-pressure-test new file mode 100755 index 00000000..10ff6ff1 Binary files /dev/null and b/apps/dns-resolver-pressure-test/dns-resolver-pressure-test differ diff --git a/apps/dns-resolver-pressure-test/main.go b/apps/dns-resolver-pressure-test/main.go new file mode 100644 index 00000000..63250698 --- /dev/null +++ b/apps/dns-resolver-pressure-test/main.go @@ -0,0 +1,74 @@ +package main + +import ( + "context" + "flag" + "fmt" + "net" + "sync/atomic" + "time" +) + +var host string +var connections int +var duration int64 +var limit int64 +var timeoutCount int64 + +func main() { + flag.StringVar(&host, "host", "", "Resolve host") + flag.IntVar(&connections, "c", 100, "Connections") + flag.Int64Var(&duration, "d", 0, "Duration(s)") + flag.Int64Var(&limit, "l", 0, "Limit(ms)") + flag.Parse() + + var count int64 = 0 + var errCount int64 = 0 + pool := make(chan interface{}, connections) + exit := make(chan bool) + var ( + min int64 = 0 + max int64 = 0 + sum int64 = 0 + ) + + go func() { + time.Sleep(time.Second * time.Duration(duration)) + exit <- true + }() +endD: + for { + select { + case pool <- nil: + go func() { + defer func() { + <-pool + }() + resolver := &net.Resolver{} + now := time.Now() + _, err := resolver.LookupIPAddr(context.Background(), host) + use := time.Since(now).Nanoseconds() / int64(time.Millisecond) + if min == 0 || use < min { + min = use + } + if use > max { + max = use + } + sum += use + if limit > 0 && use >= limit { + timeoutCount++ + } + atomic.AddInt64(&count, 1) + if err != nil { + fmt.Println(err.Error()) + atomic.AddInt64(&errCount, 1) + } + }() + case <-exit: + break endD + } + } + + fmt.Printf("request count:%d\nerror count:%d\n", count, errCount) + fmt.Printf("request time:min(%dms) max(%dms) avg(%dms) timeout(%dn)\n", min, max, sum/count, timeoutCount) +} \ No newline at end of file diff --git a/freeleaps-devops-reconciler/helm-pkg/reconciler/values.alpha.yaml b/freeleaps-devops-reconciler/helm-pkg/reconciler/values.alpha.yaml index 2e2b60ff..8db3a41a 100644 --- a/freeleaps-devops-reconciler/helm-pkg/reconciler/values.alpha.yaml +++ b/freeleaps-devops-reconciler/helm-pkg/reconciler/values.alpha.yaml @@ -1,7 +1,7 @@ replicaCount: 1 reconciler: image: - repository: null + repository: freeleaps/reconciler pullPolicy: IfNotPresent tag: snapshot-82da340 registry: docker.io diff --git a/freeleaps-secret-operator/helm-pkg/secret-operator/Chart.yaml b/freeleaps-secret-operator/helm-pkg/secret-operator/Chart.yaml new file mode 100644 index 00000000..2ea3a44d --- /dev/null +++ b/freeleaps-secret-operator/helm-pkg/secret-operator/Chart.yaml @@ -0,0 +1,17 @@ +apiVersion: v2 +name: freeleaps-secret-operator +description: A Helm chart for Freeleaps Secret Operator +type: application +version: 0.1.0 +appVersion: "0.1.0" +keywords: + - kubernetes + - operator + - secrets +maintainers: + - name: Freeleaps Team + email: support@freeleaps.com +annotations: + # This is important for CRD installation + "helm.sh/hook": pre-install,pre-upgrade + "helm.sh/hook-weight": "-5" diff --git a/freeleaps-secret-operator/helm-pkg/secret-operator/templates/NOTES.txt b/freeleaps-secret-operator/helm-pkg/secret-operator/templates/NOTES.txt new file mode 100644 index 00000000..1b9892e4 --- /dev/null +++ b/freeleaps-secret-operator/helm-pkg/secret-operator/templates/NOTES.txt @@ -0,0 +1,40 @@ +Thank you for installing {{ .Chart.Name }}. + +Your release is named {{ .Release.Name }}. + +To learn more about the release, try: + + $ helm status {{ .Release.Name }} + $ helm get all {{ .Release.Name }} + +The operator has been deployed with the following configuration: +{{- if .Values.operator.watchedNamespaces }} +- Watching namespaces: {{ .Values.operator.watchedNamespaces }} +{{- else }} +- Watching all namespaces +{{- end }} +- Leader election enabled: {{ .Values.operator.leaderElection.enabled }} +- Debug mode: {{ .Values.operator.debug }} +- API Server Port: {{ .Values.operator.apiServerPort }} + +{{- if .Values.metrics.enabled }} + +Metrics are enabled and can be accessed via service: + $ kubectl port-forward svc/{{ include "freeleaps-secret-operator.fullname" . }}-metrics {{ .Values.metrics.service.port }}:{{ .Values.metrics.service.port }} +Then visit http://localhost:{{ .Values.metrics.service.port }}/metrics +{{- end }} + +{{- if .Values.azureKeyVault.createSecret }} + +Azure Key Vault configuration has been created as a Kubernetes Secret. +{{- else if .Values.azureKeyVault.existingSecret }} +Using existing Azure Key Vault configuration from secret: {{ .Values.azureKeyVault.existingSecret }} +{{- end }} + +{{- if or .Values.jwt.createSecret .Values.jwt.existingSecret }} +JWT configuration is properly configured. +{{- end }} + +{{- if or .Values.hmac.createSecret .Values.hmac.existingSecret }} +HMAC configuration is properly configured. +{{- end }} \ No newline at end of file diff --git a/freeleaps-secret-operator/helm-pkg/secret-operator/templates/_helpers.tpl b/freeleaps-secret-operator/helm-pkg/secret-operator/templates/_helpers.tpl new file mode 100644 index 00000000..f8d56a42 --- /dev/null +++ b/freeleaps-secret-operator/helm-pkg/secret-operator/templates/_helpers.tpl @@ -0,0 +1,62 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "freeleaps-secret-operator.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "freeleaps-secret-operator.fullname" -}} +{{- if .Values.fullnameOverride }} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- $name := default .Chart.Name .Values.nameOverride }} +{{- if contains $name .Release.Name }} +{{- .Release.Name | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} +{{- end }} +{{- end }} +{{- end }} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "freeleaps-secret-operator.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "freeleaps-secret-operator.labels" -}} +helm.sh/chart: {{ include "freeleaps-secret-operator.chart" . }} +{{ include "freeleaps-secret-operator.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "freeleaps-secret-operator.selectorLabels" -}} +app.kubernetes.io/name: {{ include "freeleaps-secret-operator.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} + +{{/* +Create the name of the service account to use +*/}} +{{- define "freeleaps-secret-operator.serviceAccountName" -}} +{{- if .Values.serviceAccount.create }} +{{- default (include "freeleaps-secret-operator.fullname" .) .Values.serviceAccount.name }} +{{- else }} +{{- default "default" .Values.serviceAccount.name }} +{{- end }} +{{- end }} diff --git a/freeleaps-secret-operator/helm-pkg/secret-operator/templates/crds.yaml b/freeleaps-secret-operator/helm-pkg/secret-operator/templates/crds.yaml new file mode 100644 index 00000000..ff3dee98 --- /dev/null +++ b/freeleaps-secret-operator/helm-pkg/secret-operator/templates/crds.yaml @@ -0,0 +1,320 @@ +{{- if .Values.crds.install }} +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: freeleapssecretstores.freeleaps.com + annotations: + "helm.sh/hook": pre-install,pre-upgrade + "helm.sh/hook-weight": "-5" +spec: + group: freeleaps.com + versions: + - name: v1alpha1 + served: true + storage: true + schema: + openAPIV3Schema: + type: object + properties: + spec: + type: object + properties: + provider: + type: object + properties: + azurekv: + type: object + properties: + tenantId: + type: string + description: "Azure tenant ID" + vaultUrl: + type: string + description: "Key Vault URL (https://.vault.azure.net/)" + vaultName: + type: string + description: "Key Vault name" + subscriptionId: + type: string + description: "Azure subscription ID" + resourceGroup: + type: string + description: "Resource group containing the Key Vault" + authSecretRef: + type: object + properties: + clientId: + type: object + properties: + name: + type: string + description: "K8s Secret name containing client ID" + key: + type: string + description: "Key within the Secret" + namespace: + type: string + description: "Namespace of the K8s Secret containing client ID" + required: + - name + - key + - namespace + clientSecret: + type: object + properties: + name: + type: string + description: "K8s Secret name containing client secret" + key: + type: string + description: "Key within the Secret" + namespace: + type: string + description: "Namespace of the K8s Secret containing client secret" + required: + - name + - key + - namespace + required: + - clientId + - clientSecret + required: + - tenantId + - vaultUrl + - vaultName + - subscriptionId + - resourceGroup + - authSecretRef + status: + type: object + properties: + conditions: + type: array + items: + type: object + properties: + type: + type: string + status: + type: string + enum: ["True", "False", "Unknown"] + reason: + type: string + message: + type: string + lastTransitionTime: + type: string + format: date-time + required: + - type + - status + phase: + type: string + enum: ["Ready", "NotReady", "Error"] + additionalPrinterColumns: + - name: Phase + type: string + description: The phase of the FreeleapsSecretStore + jsonPath: .status.phase + - name: Age + type: date + jsonPath: .metadata.creationTimestamp + subresources: + status: {} + scope: Cluster + names: + plural: freeleapssecretstores + singular: freeleapssecretstore + kind: FreeleapsSecretStore +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: freeleapssecrets.freeleaps.com + annotations: + "helm.sh/hook": pre-install,pre-upgrade + "helm.sh/hook-weight": "-5" +spec: + group: freeleaps.com + versions: + - name: v1alpha1 + served: true + storage: true + schema: + openAPIV3Schema: + type: object + properties: + spec: + type: object + properties: + secretStoreRef: + type: object + properties: + kind: + type: string + enum: ["FreeleapsSecretStore"] + name: + type: string + description: "Name of the FreeleapsSecretStore" + required: + - kind + - name + target: + type: object + properties: + name: + type: string + description: "Name of the target Kubernetes Secret to create" + creationPolicy: + type: string + enum: ["Owner", "Merge"] + description: "How to handle target Secret creation" + required: + - name + - creationPolicy + data: + type: array + items: + type: object + properties: + secretKey: + type: string + description: "Key name in the target Kubernetes Secret" + remoteRef: + type: object + properties: + key: + type: string + description: "Secret key/name in the external vault" + type: + type: string + enum: ["Secret"] + description: "Type of secret (Secret, Certificate, File, etc.)" + property: + type: string + description: "Optional: specific property within the secret" + required: + - key + - type + required: + - secretKey + - remoteRef + refreshInterval: + type: string + description: "How often to refresh (default: 1h)" + default: "1h" + required: + - secretStoreRef + - target + - data + status: + type: object + x-kubernetes-preserve-unknown-fields: true + properties: + conditions: + type: array + items: + type: object + properties: + type: + type: string + status: + type: string + enum: ["True", "False", "Unknown"] + reason: + type: string + message: + type: string + lastTransitionTime: + type: string + format: date-time + required: + - type + - status + phase: + type: string + enum: ["Ready", "NotReady", "Error"] + lastSyncTime: + type: string + format: date-time + description: "Timestamp of the last successful sync" + syncedGeneration: + type: integer + format: int64 + description: "Generation of the resource that was last synced" + additionalPrinterColumns: + - name: Phase + type: string + description: The phase of the FreeleapsSecret + jsonPath: .status.phase + - name: Target + type: string + description: Name of the target Kubernetes Secret + jsonPath: .spec.target.name + - name: Last Sync + type: date + description: Last successful sync time + jsonPath: .status.lastSyncTime + - name: Age + type: date + jsonPath: .metadata.creationTimestamp + subresources: + status: {} + scope: Namespaced + names: + plural: freeleapssecrets + singular: freeleapssecret + kind: FreeleapsSecret +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: clusterkopfpeerings.kopf.dev + annotations: + "helm.sh/hook": pre-install,pre-upgrade + "helm.sh/hook-weight": "-5" +spec: + scope: Cluster + group: kopf.dev + names: + kind: ClusterKopfPeering + plural: clusterkopfpeerings + singular: clusterkopfpeering + versions: + - name: v1 + served: true + storage: true + schema: + openAPIV3Schema: + type: object + properties: + status: + type: object + x-kubernetes-preserve-unknown-fields: true +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: kopfpeerings.kopf.dev + annotations: + "helm.sh/hook": pre-install,pre-upgrade + "helm.sh/hook-weight": "-5" +spec: + scope: Namespaced + group: kopf.dev + names: + kind: KopfPeering + plural: kopfpeerings + singular: kopfpeering + versions: + - name: v1 + served: true + storage: true + schema: + openAPIV3Schema: + type: object + properties: + status: + type: object + x-kubernetes-preserve-unknown-fields: true +{{- end }} diff --git a/freeleaps-secret-operator/helm-pkg/secret-operator/templates/deployment.yaml b/freeleaps-secret-operator/helm-pkg/secret-operator/templates/deployment.yaml new file mode 100644 index 00000000..ba1b6a9d --- /dev/null +++ b/freeleaps-secret-operator/helm-pkg/secret-operator/templates/deployment.yaml @@ -0,0 +1,180 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "freeleaps-secret-operator.fullname" . }} + namespace: {{ .Release.Namespace }} + labels: + {{- include "freeleaps-secret-operator.labels" . | nindent 4 }} +spec: + replicas: {{ .Values.replicaCount }} + selector: + matchLabels: + {{- include "freeleaps-secret-operator.selectorLabels" . | nindent 6 }} + template: + metadata: + labels: + {{- include "freeleaps-secret-operator.selectorLabels" . | nindent 8 }} + {{- with .Values.podAnnotations }} + annotations: + {{- toYaml . | nindent 8 }} + {{- end }} + spec: + serviceAccountName: {{ include "freeleaps-secret-operator.serviceAccountName" . }} + securityContext: + {{- toYaml .Values.podSecurityContext | nindent 8 }} + containers: + - name: {{ .Chart.Name }} + securityContext: + {{- toYaml .Values.securityContext | nindent 12 }} + image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + ports: + - name: api + containerPort: {{ .Values.operator.apiServerPort }} + protocol: TCP + env: + # General Configuration + - name: SECRET_OPERATOR_DEBUG + value: {{ .Values.operator.debug | quote }} + - name: SECRET_OPERATOR_APISERVER_PORT + value: {{ .Values.operator.apiServerPort | quote }} + - name: K8S_CLUSTER_DOMAIN + value: {{ .Values.operator.k8sClusterDomain | quote }} + - name: AUTO_DISCOVER_K8S_CLUSTER_DOMAIN_MAX_RETRIES + value: {{ .Values.operator.autoDiscoverK8sClusterDomainMaxRetries | quote }} + - name: SECRET_OPERATOR_WATCHED_NAMESPACES + value: {{ .Values.operator.watchedNamespaces | quote }} + + # Kopf Configuration + - name: KOPF_PEERING_NAME + value: {{ .Values.operator.kopfPeeringName | quote }} + + # Azure Key Vault Configuration + {{- if .Values.azureKeyVault.createSecret }} + - name: AZURE_TENANT_ID + valueFrom: + secretKeyRef: + name: {{ include "freeleaps-secret-operator.fullname" . }}-config + key: AZURE_TENANT_ID + - name: AZURE_CLIENT_ID + valueFrom: + secretKeyRef: + name: {{ include "freeleaps-secret-operator.fullname" . }}-config + key: AZURE_CLIENT_ID + - name: AZURE_CLIENT_SECRET + valueFrom: + secretKeyRef: + name: {{ include "freeleaps-secret-operator.fullname" . }}-config + key: AZURE_CLIENT_SECRET + - name: AZURE_VAULT_URL + valueFrom: + secretKeyRef: + name: {{ include "freeleaps-secret-operator.fullname" . }}-config + key: AZURE_VAULT_URL + - name: AZURE_VAULT_NAME + valueFrom: + secretKeyRef: + name: {{ include "freeleaps-secret-operator.fullname" . }}-config + key: AZURE_VAULT_NAME + - name: AZURE_SUBSCRIPTION_ID + valueFrom: + secretKeyRef: + name: {{ include "freeleaps-secret-operator.fullname" . }}-config + key: AZURE_SUBSCRIPTION_ID + - name: AZURE_RESOURCE_GROUP + valueFrom: + secretKeyRef: + name: {{ include "freeleaps-secret-operator.fullname" . }}-config + key: AZURE_RESOURCE_GROUP + {{- else if .Values.azureKeyVault.existingSecret }} + - name: AZURE_TENANT_ID + valueFrom: + secretKeyRef: + name: {{ .Values.azureKeyVault.existingSecret }} + key: AZURE_TENANT_ID + - name: AZURE_CLIENT_ID + valueFrom: + secretKeyRef: + name: {{ .Values.azureKeyVault.existingSecret }} + key: AZURE_CLIENT_ID + - name: AZURE_CLIENT_SECRET + valueFrom: + secretKeyRef: + name: {{ .Values.azureKeyVault.existingSecret }} + key: AZURE_CLIENT_SECRET + - name: AZURE_VAULT_URL + valueFrom: + secretKeyRef: + name: {{ .Values.azureKeyVault.existingSecret }} + key: AZURE_VAULT_URL + - name: AZURE_VAULT_NAME + valueFrom: + secretKeyRef: + name: {{ .Values.azureKeyVault.existingSecret }} + key: AZURE_VAULT_NAME + - name: AZURE_SUBSCRIPTION_ID + valueFrom: + secretKeyRef: + name: {{ .Values.azureKeyVault.existingSecret }} + key: AZURE_SUBSCRIPTION_ID + - name: AZURE_RESOURCE_GROUP + valueFrom: + secretKeyRef: + name: {{ .Values.azureKeyVault.existingSecret }} + key: AZURE_RESOURCE_GROUP + {{- end }} + + # JWT Configuration + {{- if .Values.jwt.createSecret }} + - name: JWT_SECRET_KEY + valueFrom: + secretKeyRef: + name: {{ include "freeleaps-secret-operator.fullname" . }}-config + key: JWT_SECRET_KEY + - name: JWT_ALGORITHM + valueFrom: + secretKeyRef: + name: {{ include "freeleaps-secret-operator.fullname" . }}-config + key: JWT_ALGORITHM + {{- else if .Values.jwt.existingSecret }} + - name: JWT_SECRET_KEY + valueFrom: + secretKeyRef: + name: {{ .Values.jwt.existingSecret }} + key: JWT_SECRET_KEY + - name: JWT_ALGORITHM + valueFrom: + secretKeyRef: + name: {{ .Values.jwt.existingSecret }} + key: JWT_ALGORITHM + {{- end }} + + # HMAC Configuration + {{- if .Values.hmac.createSecret }} + - name: HMAC_SECRET_KEY + valueFrom: + secretKeyRef: + name: {{ include "freeleaps-secret-operator.fullname" . }}-config + key: HMAC_SECRET_KEY + {{- else if .Values.hmac.existingSecret }} + - name: HMAC_SECRET_KEY + valueFrom: + secretKeyRef: + name: {{ .Values.hmac.existingSecret }} + key: HMAC_SECRET_KEY + {{- end }} + + resources: + {{- toYaml .Values.resources | nindent 12 }} + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} \ No newline at end of file diff --git a/freeleaps-secret-operator/helm-pkg/secret-operator/templates/kopf-peering.yaml b/freeleaps-secret-operator/helm-pkg/secret-operator/templates/kopf-peering.yaml new file mode 100644 index 00000000..ad42eafe --- /dev/null +++ b/freeleaps-secret-operator/helm-pkg/secret-operator/templates/kopf-peering.yaml @@ -0,0 +1,14 @@ +apiVersion: kopf.dev/v1 +kind: ClusterKopfPeering +metadata: + name: {{ .Values.operator.kopfPeeringName }} + labels: + {{- include "freeleaps-secret-operator.labels" . | nindent 4 }} +--- +apiVersion: kopf.dev/v1 +kind: KopfPeering +metadata: + namespace: {{ .Release.Namespace }} + name: {{ .Values.operator.kopfPeeringName }} + labels: + {{- include "freeleaps-secret-operator.labels" . | nindent 4 }} diff --git a/freeleaps-secret-operator/helm-pkg/secret-operator/templates/rbac.yaml b/freeleaps-secret-operator/helm-pkg/secret-operator/templates/rbac.yaml new file mode 100644 index 00000000..a4a2d629 --- /dev/null +++ b/freeleaps-secret-operator/helm-pkg/secret-operator/templates/rbac.yaml @@ -0,0 +1,67 @@ +{{- if .Values.serviceAccount.create -}} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ include "freeleaps-secret-operator.fullname" . }} + labels: + {{- include "freeleaps-secret-operator.labels" . | nindent 4 }} +rules: + # Core resources + - apiGroups: [""] + resources: ["secrets"] + verbs: ["get", "list", "watch", "create", "update", "patch", "delete"] + - apiGroups: [""] + resources: ["events"] + verbs: ["create", "patch"] + - apiGroups: [""] + resources: ["configmaps"] + verbs: ["get", "list", "watch"] + + # Custom resources - FreeleapsSecretStore (cluster-scoped) + - apiGroups: ["freeleaps.com"] + resources: ["freeleapssecretstores"] + verbs: ["get", "list", "watch", "create", "update", "patch", "delete"] + - apiGroups: ["freeleaps.com"] + resources: ["freeleapssecretstores/status"] + verbs: ["get", "update", "patch"] + - apiGroups: ["freeleaps.com"] + resources: ["freeleapssecretstores/finalizers"] + verbs: ["update"] + + # Custom resources - FreeleapsSecret (namespaced) + - apiGroups: ["freeleaps.com"] + resources: ["freeleapssecrets"] + verbs: ["get", "list", "watch", "create", "update", "patch", "delete"] + - apiGroups: ["freeleaps.com"] + resources: ["freeleapssecrets/status"] + verbs: ["get", "update", "patch"] + - apiGroups: ["freeleaps.com"] + resources: ["freeleapssecrets/finalizers"] + verbs: ["update"] + + # Kopf operator framework requirements + - apiGroups: [""] + resources: ["events"] + verbs: ["create"] + - apiGroups: ["kopf.dev"] + resources: ["clusterkopfpeerings"] + verbs: ["list", "watch", "patch", "get"] + - apiGroups: ["apiextensions.k8s.io"] + resources: ["customresourcedefinitions"] + verbs: ["list", "watch"] +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ include "freeleaps-secret-operator.fullname" . }} + labels: + {{- include "freeleaps-secret-operator.labels" . | nindent 4 }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ include "freeleaps-secret-operator.fullname" . }} +subjects: + - kind: ServiceAccount + name: {{ include "freeleaps-secret-operator.serviceAccountName" . }} + namespace: {{ .Release.Namespace }} +{{- end }} \ No newline at end of file diff --git a/freeleaps-secret-operator/helm-pkg/secret-operator/templates/secret.yaml b/freeleaps-secret-operator/helm-pkg/secret-operator/templates/secret.yaml new file mode 100644 index 00000000..16e9c992 --- /dev/null +++ b/freeleaps-secret-operator/helm-pkg/secret-operator/templates/secret.yaml @@ -0,0 +1,27 @@ +{{- if or .Values.azureKeyVault.createSecret .Values.jwt.createSecret .Values.hmac.createSecret }} +apiVersion: v1 +kind: Secret +metadata: + name: {{ include "freeleaps-secret-operator.fullname" . }}-config + namespace: {{ .Release.Namespace }} + labels: + {{- include "freeleaps-secret-operator.labels" . | nindent 4 }} +type: Opaque +data: + {{- if .Values.azureKeyVault.createSecret }} + AZURE_TENANT_ID: {{ .Values.azureKeyVault.credentials.tenantId | b64enc | quote }} + AZURE_CLIENT_ID: {{ .Values.azureKeyVault.credentials.clientId | b64enc | quote }} + AZURE_CLIENT_SECRET: {{ .Values.azureKeyVault.credentials.clientSecret | b64enc | quote }} + AZURE_VAULT_URL: {{ .Values.azureKeyVault.credentials.vaultUrl | b64enc | quote }} + AZURE_VAULT_NAME: {{ .Values.azureKeyVault.credentials.vaultName | b64enc | quote }} + AZURE_SUBSCRIPTION_ID: {{ .Values.azureKeyVault.credentials.subscriptionId | b64enc | quote }} + AZURE_RESOURCE_GROUP: {{ .Values.azureKeyVault.credentials.resourceGroup | b64enc | quote }} + {{- end }} + {{- if .Values.jwt.createSecret }} + JWT_SECRET_KEY: {{ .Values.jwt.config.secretKey | b64enc | quote }} + JWT_ALGORITHM: {{ .Values.jwt.config.algorithm | b64enc | quote }} + {{- end }} + {{- if .Values.hmac.createSecret }} + HMAC_SECRET_KEY: {{ .Values.hmac.config.secretKey | b64enc | quote }} + {{- end }} +{{- end }} diff --git a/freeleaps-secret-operator/helm-pkg/secret-operator/templates/service.yaml b/freeleaps-secret-operator/helm-pkg/secret-operator/templates/service.yaml new file mode 100644 index 00000000..d603fa8d --- /dev/null +++ b/freeleaps-secret-operator/helm-pkg/secret-operator/templates/service.yaml @@ -0,0 +1,17 @@ +{{- if .Values.metrics.enabled }} +apiVersion: v1 +kind: Service +metadata: + name: {{ include "freeleaps-secret-operator.fullname" . }}-metrics + labels: + {{- include "freeleaps-secret-operator.labels" . | nindent 4 }} +spec: + type: {{ .Values.metrics.service.type }} + ports: + - port: {{ .Values.metrics.service.port }} + targetPort: metrics + protocol: TCP + name: metrics + selector: + {{- include "freeleaps-secret-operator.selectorLabels" . | nindent 4 }} +{{- end }} diff --git a/freeleaps-secret-operator/helm-pkg/secret-operator/templates/serviceaccount.yaml b/freeleaps-secret-operator/helm-pkg/secret-operator/templates/serviceaccount.yaml new file mode 100644 index 00000000..476c698c --- /dev/null +++ b/freeleaps-secret-operator/helm-pkg/secret-operator/templates/serviceaccount.yaml @@ -0,0 +1,12 @@ +{{- if .Values.serviceAccount.create -}} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "freeleaps-secret-operator.serviceAccountName" . }} + labels: + {{- include "freeleaps-secret-operator.labels" . | nindent 4 }} + {{- with .Values.serviceAccount.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +{{- end }} diff --git a/freeleaps-secret-operator/helm-pkg/secret-operator/values.yaml b/freeleaps-secret-operator/helm-pkg/secret-operator/values.yaml new file mode 100644 index 00000000..26db820b --- /dev/null +++ b/freeleaps-secret-operator/helm-pkg/secret-operator/values.yaml @@ -0,0 +1,109 @@ +# Default values for freeleaps-secret-operator +replicaCount: 1 + +image: + repository: freeleaps/secret-operator + pullPolicy: IfNotPresent + tag: "latest" + +imagePullSecrets: [] +nameOverride: "" +fullnameOverride: "" + +serviceAccount: + create: true + annotations: {} + name: "freeleaps-secret-operator" + +podAnnotations: {} + +podSecurityContext: {} + +securityContext: + allowPrivilegeEscalation: false + readOnlyRootFilesystem: true + runAsNonRoot: true + runAsUser: 1000 + capabilities: + drop: + - ALL + +resources: + limits: + cpu: 500m + memory: 512Mi + requests: + cpu: 100m + memory: 128Mi + +nodeSelector: {} + +tolerations: [] + +affinity: {} + +# Operator specific configuration +operator: + # General Configuration + debug: false + apiServerPort: 8080 + watchedNamespaces: "" # Empty means watch all namespaces + k8sClusterDomain: "kubernetes.default.svc.freeleaps.cluster" + autoDiscoverK8sClusterDomainMaxRetries: 5 + + # Kopf Configuration + kopfPeeringName: "freeleaps-secret-operator" + leaderElection: + enabled: true + + # Namespace where the operator will be deployed + namespace: "freeleaps-devops-system" + +# Azure Key Vault Configuration +# These values should be provided through a secret +azureKeyVault: + # If true, will create a secret for Azure Key Vault credentials + createSecret: true + # Reference to existing secret containing Azure credentials + existingSecret: "" + # Values used if createSecret is true + credentials: + tenantId: "" + clientId: "" + clientSecret: "" + vaultUrl: "" + vaultName: "" + subscriptionId: "" + resourceGroup: "" + +# JWT Configuration +jwt: + # If true, will create a secret for JWT configuration + createSecret: true + # Reference to existing secret containing JWT configuration + existingSecret: "" + # Values used if createSecret is true + config: + secretKey: "your-secret-key-change-in-production" + algorithm: "HS256" + +# HMAC Configuration +hmac: + # If true, will create a secret for HMAC configuration + createSecret: true + # Reference to existing secret containing HMAC configuration + existingSecret: "" + # Values used if createSecret is true + config: + secretKey: "your-hmac-secret-key-change-in-production" + +# CRDs configuration +crds: + install: false # Set to false if you want to manage CRDs separately + +# Metrics configuration +metrics: + enabled: false + service: + type: ClusterIP + port: 8080 diff --git a/freeleaps-secret-operator/prod/ci/Jenkinsfile b/freeleaps-secret-operator/prod/ci/Jenkinsfile new file mode 100644 index 00000000..dcccc10b --- /dev/null +++ b/freeleaps-secret-operator/prod/ci/Jenkinsfile @@ -0,0 +1,35 @@ +@Library('first-class-pipeline') _ + +executeFreeleapsPipeline { + serviceName = 'freeleaps-secret-operator' + environmentSlug = 'prod' + serviceGitBranch = 'main' + serviceGitRepo = "https://gitea.freeleaps.mathmast.com/freeleaps/freeleaps-secret-operator.git" + serviceGitRepoType = 'monorepo' + serviceGitCredentialsId = 'freeleaps-ops-git-credentials' + executeMode = 'fully' + commitMessageLintEnabled = false + components = [ + [ + name: 'secret-operator', + root: 'secretoperator', + language: 'python', + dependenciesManager: 'pip', + requirementsFile: 'requirements.txt', + buildCacheEnabled: true, + buildAgentImage: 'python:3.8-slim', + buildArtifacts: ['.'], + lintEnabled: false, + sastEnabled: false, + imageRegistry: 'docker.io', + imageRepository: 'freeleaps', + imageName: 'secret-operator', + imageBuilder: 'dind', + dockerfilePath: '../hack/Dockerfile', + imageBuildRoot: '..', + imageReleaseArchitectures: ['linux/amd64', 'linux/arm64/v8'], + registryCredentialsId: 'freeleaps-devops-docker-hub-credentials', + semanticReleaseEnabled: true + ] + ] +} \ No newline at end of file diff --git "a/temp/freeleapssecret.yaml\\" "b/temp/freeleapssecret.yaml\\" deleted file mode 100644 index e85ea392..00000000 --- "a/temp/freeleapssecret.yaml\\" +++ /dev/null @@ -1,36 +0,0 @@ -apiVersion: freeleaps.com/v1alpha1 -kind: FreeleapsSecret -metadata: - name: example-secret - namespace: freeleaps-prod -spec: - refreshInterval: 3m - secretStoreRef: - kind: FreeleapsSecretStore - name: example-secret-store - target: - name: secret-to-be-created - # Enum: Owner, Merge - # Default Value: Owner - # Owner creates the secret and sets .metadata.ownerReference of the resource - # Merge does not create the secret, but merges in the data fields to the target secret - creationPolicy: Owner - data: - - secretKey: nicolas-username-a - remoteRef: - key: username - type: Secret - - secretKey: nicolas-username-b - remoteRef: - key: username-b - type: Secret - -AzureKeyVaultSecret: username-b (username=nicolas@mathmast.com) - -AzureKeyVaultSecret: username (username=nicolas@mathmast.com) - ^ - | -FreeleapsSecret: example-secret - | - v -KubernetesSecret: secret-to-be-created (nicolas-username-a=nicolas@mathmast.com, nicolas-username-b=nicolas@mathmast.com) diff --git a/temp/freeleapssecretstore.yaml b/temp/freeleapssecretstore.yaml deleted file mode 100644 index b429c73e..00000000 --- a/temp/freeleapssecretstore.yaml +++ /dev/null @@ -1,20 +0,0 @@ -# The FreeleapsSecretStore object is cluster-wide -apiVersion: freeleaps.com/v1alpha1 -kind: FreeleapsSecretStore -metadata: - name: example-secret-store -spec: - provider: - azurekv: - tenantId: "{TENANT_ID}" - vaultUrl: "{VAULT_URL}" - vaultName: "{VAULT_NAME}" - subscriptionId: "{SUBSCRIPTION_ID}" - resourceGroup: "{RESOURCE_GROUP}" - authSecretRef: - clientId: - name: example-secret-store-azure-credentials - key: clientId - clientSecret: - name: example-secret-store-azure-credentials - key: clientSecret