From 96ec259cebebf05478a2ab6f23ea1ef1824d5f50 Mon Sep 17 00:00:00 2001 From: yyvess Date: Thu, 25 Jan 2024 19:23:14 +0100 Subject: [PATCH] feat(istio): Add Virtual service and basic Ingress support --- README.md | 27 +- .../wasmplugin/v1alpha1/types_gen.cue | 123 ++++ .../virtualservice/v1beta1/types_gen.cue | 587 ++++++++++++++++++ .../authorizationpolicy/v1/types_gen.cue | 147 +++++ .../authorizationpolicy/v1beta1/types_gen.cue | 147 +++++ templates/certificates.cue | 11 +- templates/config.cue | 111 +--- templates/configmap.cue | 350 +++++------ templates/deployment.cue | 30 +- templates/ingress.cue | 20 + templates/instance.cue | 67 ++ templates/namespace.cue | 20 + templates/networking.cue | 14 +- templates/poddisruptionbudget.cue | 3 +- templates/{service.cue => services.cue} | 52 +- templates/virtualservice.cue | 40 ++ test/certificate-values.cue | 17 +- test/certificate.yaml | 57 +- test/external-secrets-values.cue | 4 +- test/external-secrets.yaml | 19 +- test/http-values.cue | 9 +- test/http.yaml | 24 +- test/ingress-values.cue | 48 ++ test/ingress.yaml | 146 +++++ test/minimum-values.cue | 2 +- test/minimum.yaml | 18 +- test/networkpolicy-values.cue | 1 - test/networkpolicy.yaml | 161 +---- test/pdb-values.cue | 6 +- test/pdb.yaml | 31 +- test/sa-values.cue | 10 +- test/sa.yaml | 22 +- test/test.sh | 9 +- test/virtualservice-values.cue | 53 ++ test/virtualservice.yaml | 152 +++++ 35 files changed, 1959 insertions(+), 579 deletions(-) create mode 100644 cue.mod/gen/extensions.istio.io/wasmplugin/v1alpha1/types_gen.cue create mode 100644 cue.mod/gen/networking.istio.io/virtualservice/v1beta1/types_gen.cue create mode 100644 cue.mod/gen/security.istio.io/authorizationpolicy/v1/types_gen.cue create mode 100644 cue.mod/gen/security.istio.io/authorizationpolicy/v1beta1/types_gen.cue create mode 100644 templates/ingress.cue create mode 100644 templates/instance.cue create mode 100644 templates/namespace.cue rename templates/{service.cue => services.cue} (55%) create mode 100644 templates/virtualservice.cue create mode 100644 test/ingress-values.cue create mode 100644 test/ingress.yaml create mode 100644 test/virtualservice-values.cue create mode 100644 test/virtualservice.yaml diff --git a/README.md b/README.md index 989a9e0..fc8c13e 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,11 @@ # keycloak -A [timoni.sh](http://timoni.sh) module for deploying keycloak to Kubernetes clusters. +A [timoni.sh](http://timoni.sh) module for deploying [keycloak](https://www.keycloak.org/) on Kubernetes clusters. + +> [!IMPORTANT] +> Note that module in under development and is still in its infancy. +> Any feedback and PR are welcome + ## Install @@ -22,6 +27,9 @@ timoni -n keycloak apply keycloak oci://ghcr.io/yyvess/keycloak \ --values ./my-values.cue ``` +By default, the server uses the dev-file database. This is the default database that the server will use to persist data and only exists for development use-cases. The dev-file database **is not suitable for production use-cases**, and must be replaced before deploying to production. + + ## Uninstall To uninstall an instance and delete all its Kubernetes resources: @@ -32,19 +40,4 @@ timoni -n keycloak delete keycloak ## Configuration -| Key | Type | Default | Description | -|--------------------------|----------------------------------|--------------------|----------------------------------------------------------------------------------------------------------------------------------------------| -| `image: tag:` | `string` | `` | Container image tag | -| `image: digest:` | `string` | `""` | Container image digest, takes precedence over `tag` when specified | -| `image: repository:` | `string` | `docker.io/nginx` | Container image repository | -| `image: pullPolicy:` | `string` | `IfNotPresent` | [Kubernetes image pull policy](https://kubernetes.io/docs/concepts/containers/images/#image-pull-policy) | -| `metadata: labels:` | `{[ string]: string}` | `{}` | Common labels for all resources | -| `metadata: annotations:` | `{[ string]: string}` | `{}` | Common annotations for all resources | -| `pod: annotations:` | `{[ string]: string}` | `{}` | Annotations applied to pods | -| `pod: affinity:` | `corev1.#Affinity` | `{}` | [Kubernetes affinity and anti-affinity](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#affinity-and-anti-affinity) | -| `pod: imagePullSecrets:` | `[...timoniv1.#ObjectReference]` | `[]` | [Kubernetes image pull secrets](https://kubernetes.io/docs/concepts/containers/images/#specifying-imagepullsecrets-on-a-pod) | -| `replicas:` | `int` | `1` | Kubernetes deployment replicas | -| `resources:` | `timoniv1.#ResourceRequirements` | `{}` | [Kubernetes resource requests and limits](https://kubernetes.io/docs/concepts/configuration/manage-resources-containers) | -| `securityContext:` | `corev1.#SecurityContext` | `{}` | [Kubernetes container security context](https://kubernetes.io/docs/tasks/configure-pod-container/security-context) | -| `service: annotations:` | `{[ string]: string}` | `{}` | Annotations applied to the Kubernetes Service | -| `service: port:` | `int` | `80` | Kubernetes Service HTTP port | +Look samples on test folder \ No newline at end of file diff --git a/cue.mod/gen/extensions.istio.io/wasmplugin/v1alpha1/types_gen.cue b/cue.mod/gen/extensions.istio.io/wasmplugin/v1alpha1/types_gen.cue new file mode 100644 index 0000000..dde3b71 --- /dev/null +++ b/cue.mod/gen/extensions.istio.io/wasmplugin/v1alpha1/types_gen.cue @@ -0,0 +1,123 @@ +// Code generated by timoni. DO NOT EDIT. + +//timoni:generate timoni vendor crd -f https://raw.githubusercontent.com/istio/istio/master/manifests/charts/base/crds/crd-all.gen.yaml + +package v1alpha1 + +import ( + "strings" + "list" +) + +#WasmPlugin: { + // Extend the functionality provided by the Istio proxy through + // WebAssembly filters. See more details at: + // https://istio.io/docs/reference/config/proxy_extensions/wasm-plugin.html + spec!: #WasmPluginSpec + apiVersion: "extensions.istio.io/v1alpha1" + kind: "WasmPlugin" + metadata!: { + name!: strings.MaxRunes(253) & strings.MinRunes(1) & { + string + } + namespace!: strings.MaxRunes(63) & strings.MinRunes(1) & { + string + } + labels?: { + [string]: string + } + annotations?: { + [string]: string + } + } +} + +// Extend the functionality provided by the Istio proxy through +// WebAssembly filters. See more details at: +// https://istio.io/docs/reference/config/proxy_extensions/wasm-plugin.html +#WasmPluginSpec: { + // Specifies the failure behavior for the plugin due to fatal + // errors. + failStrategy?: "FAIL_CLOSE" | "FAIL_OPEN" + + // The pull behaviour to be applied when fetching Wasm module by + // either OCI image or http/https. + imagePullPolicy?: "UNSPECIFIED_POLICY" | "IfNotPresent" | "Always" + + // Credentials to use for OCI image pulling. + imagePullSecret?: strings.MaxRunes(253) & strings.MinRunes(1) + + // Specifies the criteria to determine which traffic is passed to + // WasmPlugin. + match?: [...{ + // Criteria for selecting traffic by their direction. + mode?: "UNDEFINED" | "CLIENT" | "SERVER" | "CLIENT_AND_SERVER" + + // Criteria for selecting traffic by their destination port. + ports?: [...{ + number: uint16 & >=1 + }] + }] + + // Determines where in the filter chain this `WasmPlugin` is to be + // injected. + phase?: "UNSPECIFIED_PHASE" | "AUTHN" | "AUTHZ" | "STATS" + + // The configuration that will be passed on to the plugin. + pluginConfig?: { + ... + } + + // The plugin name to be used in the Envoy configuration (used to + // be called `rootID`). + pluginName?: strings.MaxRunes(256) & strings.MinRunes(1) + + // Determines ordering of `WasmPlugins` in the same `phase`. + priority?: null | int + selector?: { + // One or more labels that indicate a specific set of pods/VMs on + // which a policy should be applied. + matchLabels?: { + [string]: string + } + } + + // SHA256 checksum that will be used to verify Wasm module or OCI + // container. + sha256?: =~"(^$|^[a-f0-9]{64}$)" + + // Optional. + targetRef?: { + // group is the group of the target resource. + group?: string + + // kind is kind of the target resource. + kind?: string + + // name is the name of the target resource. + name?: string + + // namespace is the namespace of the referent. + namespace?: string + } + + // Specifies the type of Wasm Extension to be used. + type?: "UNSPECIFIED_PLUGIN_TYPE" | "HTTP" | "NETWORK" + + // URL of a Wasm module or OCI container. + url: strings.MinRunes(1) + verificationKey?: string + vmConfig?: { + // Specifies environment variables to be injected to this VM. + env?: list.MaxItems(256) & [...{ + // Name of the environment variable. + name: strings.MaxRunes(256) & strings.MinRunes(1) + + // Value for the environment variable. + value?: strings.MaxRunes(2048) + + // Source for the environment variable's value. + valueFrom?: "INLINE" | "HOST" + }] + } +} diff --git a/cue.mod/gen/networking.istio.io/virtualservice/v1beta1/types_gen.cue b/cue.mod/gen/networking.istio.io/virtualservice/v1beta1/types_gen.cue new file mode 100644 index 0000000..883357d --- /dev/null +++ b/cue.mod/gen/networking.istio.io/virtualservice/v1beta1/types_gen.cue @@ -0,0 +1,587 @@ +// Code generated by timoni. DO NOT EDIT. + +//timoni:generate timoni vendor crd -f https://raw.githubusercontent.com/istio/istio/master/manifests/charts/base/crds/crd-all.gen.yaml + +package v1beta1 + +import "strings" + +#VirtualService: { + // Configuration affecting label/content routing, sni routing, + // etc. See more details at: + // https://istio.io/docs/reference/config/networking/virtual-service.html + spec!: #VirtualServiceSpec + apiVersion: "networking.istio.io/v1beta1" + kind: "VirtualService" + metadata!: { + name!: strings.MaxRunes(253) & strings.MinRunes(1) & { + string + } + namespace!: strings.MaxRunes(63) & strings.MinRunes(1) & { + string + } + labels?: { + [string]: string + } + annotations?: { + [string]: string + } + } +} + +// Configuration affecting label/content routing, sni routing, +// etc. See more details at: +// https://istio.io/docs/reference/config/networking/virtual-service.html +#VirtualServiceSpec: { + // A list of namespaces to which this virtual service is exported. + exportTo?: [...string] + + // The names of gateways and sidecars that should apply these + // routes. + gateways?: [...string] + + // The destination hosts to which traffic is being sent. + hosts?: [...string] + + // An ordered list of route rules for HTTP traffic. + http?: [...{ + // Cross-Origin Resource Sharing policy (CORS). + corsPolicy?: { + // Indicates whether the caller is allowed to send the actual + // request (not the preflight) using credentials. + allowCredentials?: null | bool + + // List of HTTP headers that can be used when requesting the + // resource. + allowHeaders?: [...string] + + // List of HTTP methods allowed to access the resource. + allowMethods?: [...string] + allowOrigin?: [...string] + + // String patterns that match allowed origins. + allowOrigins?: [...({} | { + exact: _ + } | { + prefix: _ + } | { + regex: _ + }) & { + exact?: string + prefix?: string + + // RE2 style regex-based match + // (https://github.com/google/re2/wiki/Syntax). + regex?: string + }] + + // A list of HTTP headers that the browsers are allowed to access. + exposeHeaders?: [...string] + + // Specifies how long the results of a preflight request can be + // cached. + maxAge?: string + } + + // Delegate is used to specify the particular VirtualService which + // can be used to define delegate HTTPRoute. + delegate?: { + // Name specifies the name of the delegate VirtualService. + name?: string + + // Namespace specifies the namespace where the delegate + // VirtualService resides. + namespace?: string + } + + // A HTTP rule can either return a direct_response, redirect or + // forward (default) traffic. + directResponse?: { + // Specifies the content of the response body. + body?: ({} | { + string: _ + } | { + bytes: _ + }) & { + // response body as base64 encoded bytes. + bytes?: string + string?: string + } + + // Specifies the HTTP response status to be returned. + status: int + } + + // Fault injection policy to apply on HTTP traffic at the client + // side. + fault?: { + // Abort Http request attempts and return error codes back to + // downstream service, giving the impression that the upstream + // service is faulty. + abort?: ({} | { + httpStatus: _ + } | { + grpcStatus: _ + } | { + http2Error: _ + }) & { + // GRPC status code to use to abort the request. + grpcStatus?: string + http2Error?: string + + // HTTP status code to use to abort the Http request. + httpStatus?: int + percentage?: { + value?: number + } + } + + // Delay requests before forwarding, emulating various failures + // such as network issues, overloaded upstream service, etc. + delay?: ({} | { + fixedDelay: _ + } | { + exponentialDelay: _ + }) & { + exponentialDelay?: string + + // Add a fixed delay before forwarding the request. + fixedDelay?: string + + // Percentage of requests on which the delay will be injected + // (0-100). + percent?: int + percentage?: { + value?: number + } + } + } + headers?: { + request?: { + add?: { + [string]: string + } + remove?: [...string] + set?: { + [string]: string + } + } + response?: { + add?: { + [string]: string + } + remove?: [...string] + set?: { + [string]: string + } + } + } + + // Match conditions to be satisfied for the rule to be activated. + match?: [...{ + // HTTP Authority values are case-sensitive and formatted as + // follows: - `exact: "value"` for exact string match - `prefix: + // "value"` for prefix-based match - `regex: "value"` for RE2 + // style regex-based match + // (https://github.com/google/re2/wiki/Syntax). + authority?: ({} | { + exact: _ + } | { + prefix: _ + } | { + regex: _ + }) & { + exact?: string + prefix?: string + + // RE2 style regex-based match + // (https://github.com/google/re2/wiki/Syntax). + regex?: string + } + + // Names of gateways where the rule should be applied. + gateways?: [...string] + + // The header keys must be lowercase and use hyphen as the + // separator, e.g. + headers?: { + [string]: ({} | { + exact: _ + } | { + prefix: _ + } | { + regex: _ + }) & { + exact?: string + prefix?: string + + // RE2 style regex-based match + // (https://github.com/google/re2/wiki/Syntax). + regex?: string + } + } + + // Flag to specify whether the URI matching should be + // case-insensitive. + ignoreUriCase?: bool + + // HTTP Method values are case-sensitive and formatted as follows: + // - `exact: "value"` for exact string match - `prefix: "value"` + // for prefix-based match - `regex: "value"` for RE2 style + // regex-based match (https://github.com/google/re2/wiki/Syntax). + method?: ({} | { + exact: _ + } | { + prefix: _ + } | { + regex: _ + }) & { + exact?: string + prefix?: string + + // RE2 style regex-based match + // (https://github.com/google/re2/wiki/Syntax). + regex?: string + } + + // The name assigned to a match. + name?: string + + // Specifies the ports on the host that is being addressed. + port?: int + + // Query parameters for matching. + queryParams?: { + [string]: ({} | { + exact: _ + } | { + prefix: _ + } | { + regex: _ + }) & { + exact?: string + prefix?: string + + // RE2 style regex-based match + // (https://github.com/google/re2/wiki/Syntax). + regex?: string + } + } + + // URI Scheme values are case-sensitive and formatted as follows: + // - `exact: "value"` for exact string match - `prefix: "value"` + // for prefix-based match - `regex: "value"` for RE2 style + // regex-based match (https://github.com/google/re2/wiki/Syntax). + scheme?: ({} | { + exact: _ + } | { + prefix: _ + } | { + regex: _ + }) & { + exact?: string + prefix?: string + + // RE2 style regex-based match + // (https://github.com/google/re2/wiki/Syntax). + regex?: string + } + + // One or more labels that constrain the applicability of a rule + // to source (client) workloads with the given labels. + sourceLabels?: { + [string]: string + } + + // Source namespace constraining the applicability of a rule to + // workloads in that namespace. + sourceNamespace?: string + + // The human readable prefix to use when emitting statistics for + // this route. + statPrefix?: string + + // URI to match values are case-sensitive and formatted as + // follows: - `exact: "value"` for exact string match - `prefix: + // "value"` for prefix-based match - `regex: "value"` for RE2 + // style regex-based match + // (https://github.com/google/re2/wiki/Syntax). + uri?: ({} | { + exact: string + } | { + prefix: string + } | { + regex: string + }) + + // withoutHeader has the same syntax with the header, but has + // opposite meaning. + withoutHeaders?: { + [string]: ({} | { + exact: _ + } | { + prefix: _ + } | { + regex: _ + }) & { + exact?: string + prefix?: string + + // RE2 style regex-based match + // (https://github.com/google/re2/wiki/Syntax). + regex?: string + } + } + }] + + // Mirror HTTP traffic to a another destination in addition to + // forwarding the requests to the intended destination. + mirror?: { + // The name of a service from the service registry. + host: string + port?: { + number?: int + } + + // The name of a subset within the service. + subset?: string + } + mirror_percent?: null | int + mirrorPercent?: null | int + mirrorPercentage?: { + value?: number + } + + // Specifies the destinations to mirror HTTP traffic in addition + // to the original destination. + mirrors?: [...{ + // Destination specifies the target of the mirror operation. + destination: { + // The name of a service from the service registry. + host: string + port?: { + number?: int + } + + // The name of a subset within the service. + subset?: string + } + percentage?: { + value?: number + } + }] + + // The name assigned to the route for debugging purposes. + name?: string + + // A HTTP rule can either return a direct_response, redirect or + // forward (default) traffic. + redirect?: ({} | { + port: _ + } | { + derivePort: _ + }) & { + // On a redirect, overwrite the Authority/Host portion of the URL + // with this value. + authority?: string + + // On a redirect, dynamically set the port: * + // FROM_PROTOCOL_DEFAULT: automatically set to 80 for HTTP and + // 443 for HTTPS. + derivePort?: "FROM_PROTOCOL_DEFAULT" | "FROM_REQUEST_PORT" + + // On a redirect, overwrite the port portion of the URL with this + // value. + port?: int + + // On a redirect, Specifies the HTTP status code to use in the + // redirect response. + redirectCode?: int + + // On a redirect, overwrite the scheme portion of the URL with + // this value. + scheme?: string + + // On a redirect, overwrite the Path portion of the URL with this + // value. + uri?: string + } + + // Retry policy for HTTP requests. + retries?: { + // Number of retries to be allowed for a given request. + attempts?: int + + // Timeout per attempt for a given request, including the initial + // call and any retries. + perTryTimeout?: string + + // Specifies the conditions under which retry takes place. + retryOn?: string + + // Flag to specify whether the retries should retry to other + // localities. + retryRemoteLocalities?: null | bool + } + + // Rewrite HTTP URIs and Authority headers. + rewrite?: { + // rewrite the Authority/Host header with this value. + authority?: string + + // rewrite the path (or the prefix) portion of the URI with this + // value. + uri?: string + + // rewrite the path portion of the URI with the specified regex. + uriRegexRewrite?: { + // RE2 style regex-based match + // (https://github.com/google/re2/wiki/Syntax). + match?: string + + // The string that should replace into matching portions of + // original URI. + rewrite?: string + } + } + + // A HTTP rule can either return a direct_response, redirect or + // forward (default) traffic. + route?: [...{ + // Destination uniquely identifies the instances of a service to + // which the request/connection should be forwarded to. + destination: { + // The name of a service from the service registry. + host: string + port?: { + number?: int + } + + // The name of a subset within the service. + subset?: string + } + headers?: { + request?: { + add?: { + [string]: string + } + remove?: [...string] + set?: { + [string]: string + } + } + response?: { + add?: { + [string]: string + } + remove?: [...string] + set?: { + [string]: string + } + } + } + + // Weight specifies the relative proportion of traffic to be + // forwarded to the destination. + weight?: int + }] + + // Timeout for HTTP requests, default is disabled. + timeout?: string + }] + + // An ordered list of route rules for opaque TCP traffic. + tcp?: [...{ + // Match conditions to be satisfied for the rule to be activated. + match?: [...{ + // IPv4 or IPv6 ip addresses of destination with optional subnet. + destinationSubnets?: [...string] + + // Names of gateways where the rule should be applied. + gateways?: [...string] + + // Specifies the port on the host that is being addressed. + port?: int + + // One or more labels that constrain the applicability of a rule + // to workloads with the given labels. + sourceLabels?: { + [string]: string + } + + // Source namespace constraining the applicability of a rule to + // workloads in that namespace. + sourceNamespace?: string + sourceSubnet?: string + }] + + // The destination to which the connection should be forwarded to. + route?: [...{ + // Destination uniquely identifies the instances of a service to + // which the request/connection should be forwarded to. + destination: { + // The name of a service from the service registry. + host: string + port?: { + number?: int + } + + // The name of a subset within the service. + subset?: string + } + + // Weight specifies the relative proportion of traffic to be + // forwarded to the destination. + weight?: int + }] + }] + + // An ordered list of route rule for non-terminated TLS & HTTPS + // traffic. + tls?: [...{ + // Match conditions to be satisfied for the rule to be activated. + match: [...{ + // IPv4 or IPv6 ip addresses of destination with optional subnet. + destinationSubnets?: [...string] + + // Names of gateways where the rule should be applied. + gateways?: [...string] + + // Specifies the port on the host that is being addressed. + port?: int + + // SNI (server name indicator) to match on. + sniHosts: [...string] + + // One or more labels that constrain the applicability of a rule + // to workloads with the given labels. + sourceLabels?: { + [string]: string + } + + // Source namespace constraining the applicability of a rule to + // workloads in that namespace. + sourceNamespace?: string + }] + + // The destination to which the connection should be forwarded to. + route?: [...{ + // Destination uniquely identifies the instances of a service to + // which the request/connection should be forwarded to. + destination: { + // The name of a service from the service registry. + host: string + port?: { + number?: int + } + + // The name of a subset within the service. + subset?: string + } + + // Weight specifies the relative proportion of traffic to be + // forwarded to the destination. + weight?: int + }] + }] +} diff --git a/cue.mod/gen/security.istio.io/authorizationpolicy/v1/types_gen.cue b/cue.mod/gen/security.istio.io/authorizationpolicy/v1/types_gen.cue new file mode 100644 index 0000000..f536e6f --- /dev/null +++ b/cue.mod/gen/security.istio.io/authorizationpolicy/v1/types_gen.cue @@ -0,0 +1,147 @@ +// Code generated by timoni. DO NOT EDIT. + +//timoni:generate timoni vendor crd -f https://raw.githubusercontent.com/istio/istio/master/manifests/charts/base/crds/crd-all.gen.yaml + +package v1 + +import "strings" + +#AuthorizationPolicy: { + // Configuration for access control on workloads. See more details + // at: + // https://istio.io/docs/reference/config/security/authorization-policy.html + spec!: #AuthorizationPolicySpec + apiVersion: "security.istio.io/v1" + kind: "AuthorizationPolicy" + metadata!: { + name!: strings.MaxRunes(253) & strings.MinRunes(1) & { + string + } + namespace!: strings.MaxRunes(63) & strings.MinRunes(1) & { + string + } + labels?: { + [string]: string + } + annotations?: { + [string]: string + } + } +} + +// Configuration for access control on workloads. See more details +// at: +// https://istio.io/docs/reference/config/security/authorization-policy.html +#AuthorizationPolicySpec: ({} | { + provider: _ +}) & { + // Optional. + action?: "ALLOW" | "DENY" | "AUDIT" | "CUSTOM" + provider?: { + // Specifies the name of the extension provider. + name?: string + } + + // Optional. + rules?: [...{ + // Optional. + from?: [...{ + // Source specifies the source of a request. + source?: { + // Optional. + ipBlocks?: [...string] + + // Optional. + namespaces?: [...string] + + // Optional. + notIpBlocks?: [...string] + + // Optional. + notNamespaces?: [...string] + + // Optional. + notPrincipals?: [...string] + + // Optional. + notRemoteIpBlocks?: [...string] + + // Optional. + notRequestPrincipals?: [...string] + + // Optional. + principals?: [...string] + + // Optional. + remoteIpBlocks?: [...string] + + // Optional. + requestPrincipals?: [...string] + } + }] + + // Optional. + to?: [...{ + // Operation specifies the operation of a request. + operation?: { + // Optional. + hosts?: [...string] + + // Optional. + methods?: [...string] + + // Optional. + notHosts?: [...string] + + // Optional. + notMethods?: [...string] + + // Optional. + notPaths?: [...string] + + // Optional. + notPorts?: [...string] + + // Optional. + paths?: [...string] + + // Optional. + ports?: [...string] + } + }] + + // Optional. + when?: [...{ + // The name of an Istio attribute. + key: string + + // Optional. + notValues?: [...string] + + // Optional. + values?: [...string] + }] + }] + selector?: { + // One or more labels that indicate a specific set of pods/VMs on + // which a policy should be applied. + matchLabels?: { + [string]: string + } + } + + // Optional. + targetRef?: { + // group is the group of the target resource. + group?: string + + // kind is kind of the target resource. + kind?: string + + // name is the name of the target resource. + name?: string + + // namespace is the namespace of the referent. + namespace?: string + } +} diff --git a/cue.mod/gen/security.istio.io/authorizationpolicy/v1beta1/types_gen.cue b/cue.mod/gen/security.istio.io/authorizationpolicy/v1beta1/types_gen.cue new file mode 100644 index 0000000..f774862 --- /dev/null +++ b/cue.mod/gen/security.istio.io/authorizationpolicy/v1beta1/types_gen.cue @@ -0,0 +1,147 @@ +// Code generated by timoni. DO NOT EDIT. + +//timoni:generate timoni vendor crd -f https://raw.githubusercontent.com/istio/istio/master/manifests/charts/base/crds/crd-all.gen.yaml + +package v1beta1 + +import "strings" + +#AuthorizationPolicy: { + // Configuration for access control on workloads. See more details + // at: + // https://istio.io/docs/reference/config/security/authorization-policy.html + spec!: #AuthorizationPolicySpec + apiVersion: "security.istio.io/v1beta1" + kind: "AuthorizationPolicy" + metadata!: { + name!: strings.MaxRunes(253) & strings.MinRunes(1) & { + string + } + namespace!: strings.MaxRunes(63) & strings.MinRunes(1) & { + string + } + labels?: { + [string]: string + } + annotations?: { + [string]: string + } + } +} + +// Configuration for access control on workloads. See more details +// at: +// https://istio.io/docs/reference/config/security/authorization-policy.html +#AuthorizationPolicySpec: ({} | { + provider: _ +}) & { + // Optional. + action?: "ALLOW" | "DENY" | "AUDIT" | "CUSTOM" + provider?: { + // Specifies the name of the extension provider. + name?: string + } + + // Optional. + rules?: [...{ + // Optional. + from?: [...{ + // Source specifies the source of a request. + source?: { + // Optional. + ipBlocks?: [...string] + + // Optional. + namespaces?: [...string] + + // Optional. + notIpBlocks?: [...string] + + // Optional. + notNamespaces?: [...string] + + // Optional. + notPrincipals?: [...string] + + // Optional. + notRemoteIpBlocks?: [...string] + + // Optional. + notRequestPrincipals?: [...string] + + // Optional. + principals?: [...string] + + // Optional. + remoteIpBlocks?: [...string] + + // Optional. + requestPrincipals?: [...string] + } + }] + + // Optional. + to?: [...{ + // Operation specifies the operation of a request. + operation?: { + // Optional. + hosts?: [...string] + + // Optional. + methods?: [...string] + + // Optional. + notHosts?: [...string] + + // Optional. + notMethods?: [...string] + + // Optional. + notPaths?: [...string] + + // Optional. + notPorts?: [...string] + + // Optional. + paths?: [...string] + + // Optional. + ports?: [...string] + } + }] + + // Optional. + when?: [...{ + // The name of an Istio attribute. + key: string + + // Optional. + notValues?: [...string] + + // Optional. + values?: [...string] + }] + }] + selector?: { + // One or more labels that indicate a specific set of pods/VMs on + // which a policy should be applied. + matchLabels?: { + [string]: string + } + } + + // Optional. + targetRef?: { + // group is the group of the target resource. + group?: string + + // kind is kind of the target resource. + kind?: string + + // name is the name of the target resource. + name?: string + + // namespace is the namespace of the referent. + namespace?: string + } +} diff --git a/templates/certificates.cue b/templates/certificates.cue index 8402da9..5a8a3b6 100644 --- a/templates/certificates.cue +++ b/templates/certificates.cue @@ -18,8 +18,8 @@ import ( } #JksSecret: timoniv1.#ImmutableConfig & { - #config: #Config - #Kind: timoniv1.#SecretKind + #config: #Config + #Kind: timoniv1.#SecretKind #Meta: { name: "\(#config.metadata.name)-jks-pwd" #Version: #config.moduleVersion @@ -34,10 +34,9 @@ import ( #JKS: v1.#Certificate & { #config: #Config #secretName: string - metadata: { - name: "\(#config.metadata.name)-jks" - namespace: #config.metadata.namespace - labels: #config.metadata.labels + metadata: timoniv1.#MetaComponent & { + #Meta: #config.metadata + #Component: "jks" } spec: #config.jks & { issuerRef: { diff --git a/templates/config.cue b/templates/config.cue index 51fcaec..1d34d62 100644 --- a/templates/config.cue +++ b/templates/config.cue @@ -7,6 +7,7 @@ import ( issuerv1 "cert-manager.io/issuer/v1" policyv1 "k8s.io/api/policy/v1" netv1 "k8s.io/api/networking/v1" + vsv1beta1 "networking.istio.io/virtualservice/v1beta1" ) #secretReference: { @@ -54,8 +55,8 @@ import ( // By default, the container requests 10m CPU and 32Mi memory. resources: timoniv1.#ResourceRequirements | *{ requests: { - cpu: *"10m" | timoniv1.#CPUQuantity - memory: *"32Mi" | timoniv1.#MemoryQuantity + cpu: *"200m" | timoniv1.#CPUQuantity + memory: *"768Mi" | timoniv1.#MemoryQuantity } } @@ -104,6 +105,8 @@ import ( // App settings. command: [...string] | *["/opt/keycloak/bin/kc.sh", "start"] + ha: replicas > 1 + serviceAccountCreate: *false | bool serviceAccount: corev1.#ServiceAccount @@ -127,19 +130,38 @@ import ( issuerCreate: *false | bool issuer: issuerv1.#IssuerSpec - pdbCreate: bool | *(replicas > 1) - pdbSpec: policyv1.#PodDisruptionBudgetSpec & { + pdbCreate: bool | *ha + pdb: policyv1.#PodDisruptionBudgetSpec & { minAvailable: *1 | int & >0 & <=65535 } networkPolicyCreate: *false | bool networkPolicyRules: [... netv1.#NetworkPolicyIngressRule] - // Setup distibuing cache for HA - cacheIspn: bool | *(replicas > 1) + virtualService?: vsv1beta1.#VirtualServiceSpec + + ingress?: netv1.#IngressSpec + + + fileDb: false | *(envs.KC_DB == "dev-file" | envs.KC_DB == _|_) + + jgroups: { + name: *"jgroups" | string + port: *7800 | int & >0 & <=65535 + } envs: { - KC_DB?: "dev-file" | "dev-mem" | "postgres" | "mariadb" | "mssql" | "mysql" | "oracle" + if !ha { + KC_DB?: "dev-mem" | "dev-file" | "postgres" | "mariadb" | "mssql" | "mysql" | "oracle" + KC_CACHE: "local" + JAVA_OPTS_APPEND?: string + } + if ha { + KC_DB!: "postgres" | "mariadb" | "mssql" | "mysql" | "oracle" + KC_CACHE: "ispn" + KC_CACHE_CONFIG_FILE: "cache-ispn.xml" + JAVA_OPTS_APPEND: *"-Djgroups.dns.query=\( metadata.name )-\( jgroups.name )" | string + } KC_HEALTH_ENABLED: true KC_HTTP_ENABLED: *true | false KC_HTTP_PORT?: int & >0 & <=65535 @@ -160,10 +182,7 @@ import ( KC_DB_URL?: string | #secretReference KC_DB_USERNAME?: string | #secretReference KC_DB_PASSWORD?: string | #secretReference - KC_CACHE?: "local" | "ispn" - KC_CACHE_CONFIG_FILE?: string KC_CACHE_STACK: *"kubernetes" | "tcp" | "udp" | "ec2" | "azure" | "google" - JAVA_OPTS_APPEND?: string KC_LOG_LEVEL?: string KC_LOG_CONSOLE_OUTPUT?: string KC_LOG_CONSOLE_FORMAT?: string @@ -175,77 +194,5 @@ import ( KC_HTTPS_CERTIFICATE_FILE?: string KC_HTTPS_CERTIFICATE_KEY_FILE?: string } - - } - - fileDb: false | *(envs.KC_DB == "dev-file" | envs.KC_DB == _|_) - - jgroups: { - name: *"jgroups" | string - port: *7800 | int & >0 & <=65535 - } -} - -// Instance takes the config values and outputs the Kubernetes objects. -#Instance: { - config: #Config & { - if config.cacheIspn { - envs: { - KC_CACHE_CONFIG_FILE: string | *"cache-ispn.xml" - KC_CACHE: "local" | *"ispn" - JAVA_OPTS_APPEND: *"-Djgroups.dns.query=\( config.metadata.name )-\( config.jgroups.name )" | string - } - } - if !config.cacheIspn { - envs: { - KC_CACHE: *"local" | "ispn" - } - } - } - objects: { - if config.serviceAccountCreate { - sa: #ServiceAccount & {#config: config} - } - if config.certificateCreate { - cert: #Certificate & {#config: config} - } - if config.jksCreate { - // Next version of certmanager the secret should optional and can be remove - // https://github.com/cert-manager/cert-manager/pull/6657#discussion_r1464958155 - jksPassword: #JksSecret & {#config: config} - jks: #JKS & { - #config: config - #secretName: jksPassword.metadata.name - } - } - if config.issuerCreate { - issuer: #Issuer & {#config: config} - } - svcHttp: #ServiceHttp & {#config: config} - if config.cacheIspn { - svcJgroup: #ServiceJgroup & {#config: config} - cm: #ConfigMapIspn & {#config: config} - } - - if config.pdbCreate { - pdb: #PodDisruptionBudget & {#config: config} - } - - if config.networkPolicyCreate { - networkPolicy: #NetworkPolicy & { - #config: config - } - } - - deploy: #Deployment & { - #config: config - #cmName: *objects.cm.metadata.name | "" - if objects.cert.spec.secretName != _|_ { - #certSecretName: objects.cert.spec.secretName - } - if objects.jks.spec.secretName != _|_ { - #jksSecretName: objects.jks.spec.secretName - } - } } } diff --git a/templates/configmap.cue b/templates/configmap.cue index 7e9ac39..bdbf466 100644 --- a/templates/configmap.cue +++ b/templates/configmap.cue @@ -10,185 +10,185 @@ import ( #Meta: #config.metadata #Data: { if #config.jksCreate { - "cache-ispn.xml": """ - - - - - - - - + "cache-ispn.xml": """ + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - """ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + """ } if !#config.jksCreate { - "cache-ispn.xml": """ - - - - - - - - + "cache-ispn.xml": """ + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - """ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + """ } } } diff --git a/templates/deployment.cue b/templates/deployment.cue index 7e9e737..752ad71 100644 --- a/templates/deployment.cue +++ b/templates/deployment.cue @@ -61,7 +61,7 @@ import ( protocol: "TCP" } }, - if #config.cacheIspn { + if #config.ha { { name: "jgroups" containerPort: 7800 @@ -75,31 +75,31 @@ import ( port: "http" scheme: "HTTP" } - failureThreshold: 30 - periodSeconds: 15 + initialDelaySeconds: 30 + failureThreshold: 30 + periodSeconds: 15 httpGet: { path: "/health" port: "http" scheme: "HTTP" } } - livenessProbe: { - successThreshold: 1 - initialDelaySeconds: 30 - periodSeconds: 30 - timeoutSeconds: 10 - failureThreshold: 3 + readinessProbe: { + timeoutSeconds: 10 + periodSeconds: 15 + successThreshold: 1 + failureThreshold: 3 httpGet: { path: "/health" port: "http" scheme: "HTTP" } } - readinessProbe: { - failureThreshold: 3 - successThreshold: 1 + livenessProbe: { + periodSeconds: 30 timeoutSeconds: 10 - periodSeconds: 15 + successThreshold: 1 + failureThreshold: 3 httpGet: { path: "/health" port: "http" @@ -107,7 +107,7 @@ import ( } } volumeMounts: [ - if #config.cacheIspn { + if #config.ha { { mountPath: "/opt/keycloak/conf" name: "cache" @@ -147,7 +147,7 @@ import ( } } }, - if #config.cacheIspn { + if #config.ha { { name: "cache" configMap: { diff --git a/templates/ingress.cue b/templates/ingress.cue new file mode 100644 index 0000000..2b8a06f --- /dev/null +++ b/templates/ingress.cue @@ -0,0 +1,20 @@ +package templates + +import ( + netv1 "k8s.io/api/networking/v1" +) + +#Ingress: netv1.#Ingress & { + apiVersion: "networking.k8s.io/v1" + kind: "Ingress" + #config: #Config + metadata: { + name: #config.metadata.name + namespace: #config.metadata.namespace + labels: #config.metadata.labels + if #config.metadata.annotations != _|_ { + annotations: (#config & #config.ingress).metadata.annotations + } + } + spec: #config.ingress +} diff --git a/templates/instance.cue b/templates/instance.cue new file mode 100644 index 0000000..c53a5b1 --- /dev/null +++ b/templates/instance.cue @@ -0,0 +1,67 @@ +package templates + +// Instance takes the config values and outputs the Kubernetes objects. +#Instance: { + config: #Config + objects: { + + namespace: #Namespace & {#config: config} + + if config.serviceAccountCreate { + sa: #ServiceAccount & {#config: config} + } + if config.certificateCreate { + cert: #Certificate & {#config: config} + } + if config.jksCreate { + // Next version of certmanager the secret should optional and can be remove + // https://github.com/cert-manager/cert-manager/pull/6657#discussion_r1464958155 + jksPassword: #JksSecret & {#config: config} + jks: #JKS & { + #config: config + #secretName: jksPassword.metadata.name + } + } + if config.issuerCreate { + issuer: #Issuer & {#config: config} + } + svcHttp: #ServiceHttp & {#config: config} + if config.ha { + svcJgroup: #ServiceJgroup & {#config: config} + cm: #ConfigMapIspn & {#config: config} + } + + if config.pdbCreate { + pdb: #PodDisruptionBudget & {#config: config} + } + + if config.networkPolicyCreate { + networkPolicy: #NetworkPolicy & { + #config: config + } + } + + if config.virtualService != _|_ { + virtualService: #VirtualService & { + #config: config + } + } + + if config.ingress != _|_ { + virtualService: #Ingress & { + #config: config + } + } + + deploy: #Deployment & { + #config: config + #cmName: *objects.cm.metadata.name | "" + if objects.cert.spec.secretName != _|_ { + #certSecretName: objects.cert.spec.secretName + } + if objects.jks.spec.secretName != _|_ { + #jksSecretName: objects.jks.spec.secretName + } + } + } +} diff --git a/templates/namespace.cue b/templates/namespace.cue new file mode 100644 index 0000000..fc6e693 --- /dev/null +++ b/templates/namespace.cue @@ -0,0 +1,20 @@ +package templates + +import ( + corev1 "k8s.io/api/core/v1" +) + +#Namespace: corev1.#Namespace & { + #config: #Config + apiVersion: "v1" + kind: "Namespace" + metadata: { + name: #config.metadata.namespace + if #config.virtualService != _|_ { + labels: "istio-injection": "enabled" + } + if #config.metadata.annotations != _|_ { + annotations: #config.metadata.annotations + } + } +} diff --git a/templates/networking.cue b/templates/networking.cue index 93766c6..dd70d5b 100644 --- a/templates/networking.cue +++ b/templates/networking.cue @@ -19,7 +19,19 @@ import ( for v in #config.networkPolicyRules { v }, - if #config.cacheIspn { + // Allow all pod in the same namespance + { + from: [{ + podSelector: {} + }, + ] + ports: [{ + protocol: "TCP" + port: #config.service.port + }, + ]}, + // Allow Keycloak Jgroup + if #config.ha { { from: [{ podSelector: { diff --git a/templates/poddisruptionbudget.cue b/templates/poddisruptionbudget.cue index 0ef2d5b..667dc53 100644 --- a/templates/poddisruptionbudget.cue +++ b/templates/poddisruptionbudget.cue @@ -9,8 +9,7 @@ import ( kind: "PodDisruptionBudget" #config: #Config metadata: #config.metadata - spec: #config.pdbSpec & { - + spec: #config.pdb & { selector: { matchLabels: { #config.selector.labels diff --git a/templates/service.cue b/templates/services.cue similarity index 55% rename from templates/service.cue rename to templates/services.cue index eed0acb..0ba6a31 100644 --- a/templates/service.cue +++ b/templates/services.cue @@ -2,15 +2,17 @@ package templates import ( corev1 "k8s.io/api/core/v1" + timoniv1 "timoni.sh/core/v1alpha1" ) #Service: corev1.#Service & { - #config: #Config apiVersion: "v1" kind: "Service" - metadata: { - namespace: #config.metadata.namespace - labels: #config.metadata.labels + #config: #Config + #component: string + metadata: timoniv1.#MetaComponent & { + #Meta: #config.metadata + #Component: #component if #config.service.annotations != _|_ { metadata: annotations: #config.service.annotations } @@ -22,39 +24,35 @@ import ( } #ServiceHttp: #Service & { - #config: #Config - metadata: { - name: #config.metadata.name - } + #config: #Config + #component: "web" spec: { ports: [ if !#config.service.https { - { - name: "http" - appProtocol: "http" - port: #config.service.port - protocol: "TCP" - targetPort: "http" - }, + { + name: "http" + appProtocol: "http" + port: #config.service.port + protocol: "TCP" + targetPort: "http" + } }, if #config.service.https { - { - name: "https" - appProtocol: "https" - port: #config.service.port - protocol: "TCP" - targetPort: "https" - } - } + { + name: "https" + appProtocol: "https" + port: #config.service.port + protocol: "TCP" + targetPort: "https" + } + }, ] } } #ServiceJgroup: #Service & { - #config: #Config - metadata: { - name: "\( #config.metadata.name )-\( #config.jgroups.name )" - } + #config: #Config + #component: "jgroup" spec: { ports: [ { diff --git a/templates/virtualservice.cue b/templates/virtualservice.cue new file mode 100644 index 0000000..123a6b1 --- /dev/null +++ b/templates/virtualservice.cue @@ -0,0 +1,40 @@ +package templates + +import ( + vsv1beta1 "networking.istio.io/virtualservice/v1beta1" +) + +#VirtualService: vsv1beta1.#VirtualService & { + #config: #Config + metadata: #config.metadata + spec: #config.virtualService & { + http: [ + { + match: [{ + uri: { + prefix: "/health" + }}, { + uri: { + prefix: "/metrics" + }}, + ] + directResponse: { + status: 403 + } + }, + { + match: [{ + uri: { + prefix: *"/" | #config.envs.KC_HOSTNAME_PATH + }}, + ] + route: [{ + destination: { + host: "\( #config.metadata.name )-web" + port: { + number: #config.service.port + } + }}] + }] + } +} diff --git a/test/certificate-values.cue b/test/certificate-values.cue index 2c77248..d6085fe 100644 --- a/test/certificate-values.cue +++ b/test/certificate-values.cue @@ -14,17 +14,11 @@ values: { tag: "23.0" } - metadata: { - annotations: { - custom_annotation: "sleep" - } - } - service: https: true - issuerCreate: true - jksCreate: true - certificateCreate: true + issuerCreate: true + jksCreate: true + certificateCreate: true networkPolicyCreate: true issuer: { @@ -43,12 +37,9 @@ values: { } envs: { - KEYCLOAK_ADMIN: "admin" KEYCLOAK_ADMIN_PASSWORD: "admin" + KC_DB: "postgres" KC_DB_USERNAME: "admin" KC_DB_PASSWORD: "admin" - KC_HOSTNAME_STRICT: false - KC_HOSTNAME_STRICT_HTTPS: false - KC_LOG_LEVEL: "DEBUG" } } diff --git a/test/certificate.yaml b/test/certificate.yaml index 59a9117..8c5b52b 100644 --- a/test/certificate.yaml +++ b/test/certificate.yaml @@ -1,8 +1,11 @@ +apiVersion: v1 +kind: Namespace +metadata: + name: test +--- apiVersion: cert-manager.io/v1 kind: Certificate metadata: - annotations: - custom_annotation: sleep labels: app.kubernetes.io/managed-by: timoni app.kubernetes.io/name: keycloak @@ -31,8 +34,6 @@ apiVersion: v1 immutable: true kind: Secret metadata: - annotations: - custom_annotation: sleep labels: app.kubernetes.io/managed-by: timoni app.kubernetes.io/name: keycloak-jks-pwd @@ -46,6 +47,7 @@ apiVersion: cert-manager.io/v1 kind: Certificate metadata: labels: + app.kubernetes.io/component: jks app.kubernetes.io/managed-by: timoni app.kubernetes.io/name: keycloak app.kubernetes.io/version: 0.0.0-devel @@ -68,8 +70,6 @@ spec: apiVersion: cert-manager.io/v1 kind: Issuer metadata: - annotations: - custom_annotation: sleep labels: app.kubernetes.io/managed-by: timoni app.kubernetes.io/name: keycloak @@ -83,10 +83,11 @@ apiVersion: v1 kind: Service metadata: labels: + app.kubernetes.io/component: web app.kubernetes.io/managed-by: timoni app.kubernetes.io/name: keycloak app.kubernetes.io/version: 0.0.0-devel - name: keycloak + name: keycloak-web namespace: test spec: ports: @@ -103,10 +104,11 @@ apiVersion: v1 kind: Service metadata: labels: + app.kubernetes.io/component: jgroup app.kubernetes.io/managed-by: timoni app.kubernetes.io/name: keycloak app.kubernetes.io/version: 0.0.0-devel - name: keycloak-jgroups + name: keycloak-jgroup namespace: test spec: ports: @@ -165,8 +167,6 @@ data: immutable: true kind: ConfigMap metadata: - annotations: - custom_annotation: sleep labels: app.kubernetes.io/managed-by: timoni app.kubernetes.io/name: keycloak @@ -177,8 +177,6 @@ metadata: apiVersion: policy/v1 kind: PodDisruptionBudget metadata: - annotations: - custom_annotation: sleep labels: app.kubernetes.io/managed-by: timoni app.kubernetes.io/name: keycloak @@ -194,8 +192,6 @@ spec: apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: - annotations: - custom_annotation: sleep labels: app.kubernetes.io/managed-by: timoni app.kubernetes.io/name: keycloak @@ -204,6 +200,11 @@ metadata: namespace: test spec: ingress: + - from: + - podSelector: {} + ports: + - port: 8443 + protocol: TCP - from: - podSelector: matchLabels: @@ -220,8 +221,6 @@ spec: apiVersion: apps/v1 kind: Deployment metadata: - annotations: - custom_annotation: sleep labels: app.kubernetes.io/managed-by: timoni app.kubernetes.io/name: keycloak @@ -243,14 +242,18 @@ spec: - /opt/keycloak/bin/kc.sh - start env: + - name: KC_DB + value: postgres + - name: KC_CACHE + value: ispn + - name: JAVA_OPTS_APPEND + value: -Djgroups.dns.query=keycloak-jgroups + - name: KC_CACHE_CONFIG_FILE + value: cache-ispn.xml - name: KC_HEALTH_ENABLED value: "true" - name: KC_HTTP_ENABLED value: "true" - - name: KC_HOSTNAME_STRICT - value: "false" - - name: KC_HOSTNAME_STRICT_HTTPS - value: "false" - name: KEYCLOAK_ADMIN value: admin - name: KEYCLOAK_ADMIN_PASSWORD @@ -259,16 +262,8 @@ spec: value: admin - name: KC_DB_PASSWORD value: admin - - name: KC_CACHE - value: ispn - - name: KC_CACHE_CONFIG_FILE - value: cache-ispn.xml - name: KC_CACHE_STACK value: kubernetes - - name: JAVA_OPTS_APPEND - value: -Djgroups.dns.query=keycloak-jgroups - - name: KC_LOG_LEVEL - value: DEBUG - name: KC_HTTPS_CERTIFICATE_FILE value: /certs/tls.crt - name: KC_HTTPS_CERTIFICATE_KEY_FILE @@ -281,7 +276,6 @@ spec: path: /health port: http scheme: HTTP - initialDelaySeconds: 30 periodSeconds: 30 successThreshold: 1 timeoutSeconds: 10 @@ -307,8 +301,8 @@ spec: timeoutSeconds: 10 resources: requests: - cpu: 10m - memory: 32Mi + cpu: 200m + memory: 768Mi securityContext: allowPrivilegeEscalation: false capabilities: @@ -325,6 +319,7 @@ spec: path: /health port: http scheme: HTTP + initialDelaySeconds: 30 periodSeconds: 15 volumeMounts: - mountPath: /opt/keycloak/conf diff --git a/test/external-secrets-values.cue b/test/external-secrets-values.cue index f027044..e3d7d31 100644 --- a/test/external-secrets-values.cue +++ b/test/external-secrets-values.cue @@ -25,11 +25,11 @@ values: { envs: { KEYCLOAK_ADMIN: { name: "existing-secret" - key: "keycloak-admin-user" + key: "keycloak-admin-user" } KEYCLOAK_ADMIN_PASSWORD: { name: "existing-secret" - key: "keycloak-admin-password" + key: "keycloak-admin-password" } } } diff --git a/test/external-secrets.yaml b/test/external-secrets.yaml index 2171a16..1ee0a8c 100644 --- a/test/external-secrets.yaml +++ b/test/external-secrets.yaml @@ -1,3 +1,8 @@ +apiVersion: v1 +kind: Namespace +metadata: + name: test +--- apiVersion: cert-manager.io/v1 kind: Certificate metadata: @@ -33,6 +38,7 @@ apiVersion: cert-manager.io/v1 kind: Certificate metadata: labels: + app.kubernetes.io/component: jks app.kubernetes.io/managed-by: timoni app.kubernetes.io/name: keycloak app.kubernetes.io/version: 0.0.0-devel @@ -56,10 +62,11 @@ apiVersion: v1 kind: Service metadata: labels: + app.kubernetes.io/component: web app.kubernetes.io/managed-by: timoni app.kubernetes.io/name: keycloak app.kubernetes.io/version: 0.0.0-devel - name: keycloak + name: keycloak-web namespace: test spec: ports: @@ -96,12 +103,12 @@ spec: - /opt/keycloak/bin/kc.sh - start env: + - name: KC_CACHE + value: local - name: KC_HEALTH_ENABLED value: "true" - name: KC_HTTP_ENABLED value: "true" - - name: KC_CACHE - value: local - name: KC_CACHE_STACK value: kubernetes - name: KC_HTTPS_CERTIFICATE_FILE @@ -126,7 +133,6 @@ spec: path: /health port: http scheme: HTTP - initialDelaySeconds: 30 periodSeconds: 30 successThreshold: 1 timeoutSeconds: 10 @@ -146,8 +152,8 @@ spec: timeoutSeconds: 10 resources: requests: - cpu: 10m - memory: 32Mi + cpu: 200m + memory: 768Mi securityContext: allowPrivilegeEscalation: false capabilities: @@ -164,6 +170,7 @@ spec: path: /health port: http scheme: HTTP + initialDelaySeconds: 30 periodSeconds: 15 volumeMounts: - mountPath: /certs diff --git a/test/http-values.cue b/test/http-values.cue index 625e859..928f782 100644 --- a/test/http-values.cue +++ b/test/http-values.cue @@ -15,12 +15,6 @@ values: { tag: "23.0" } - metadata: { - annotations: { - custom_annotation: "sleep" - } - } - envs: { KEYCLOAK_ADMIN: "admin" KEYCLOAK_ADMIN_PASSWORD: "admin" @@ -30,6 +24,7 @@ values: { KC_HOSTNAME_URL: "http://localhost:8080/" KC_HOSTNAME_STRICT: false KC_HOSTNAME_STRICT_HTTPS: false - KC_LOG_LEVEL: "DEBUG" + + KC_LOG_LEVEL: "DEBUG" } } diff --git a/test/http.yaml b/test/http.yaml index 76b91a3..7edc132 100644 --- a/test/http.yaml +++ b/test/http.yaml @@ -1,12 +1,18 @@ apiVersion: v1 +kind: Namespace +metadata: + name: zel-test +--- +apiVersion: v1 kind: Service metadata: labels: + app.kubernetes.io/component: web app.kubernetes.io/managed-by: timoni app.kubernetes.io/name: keycloak app.kubernetes.io/version: 0.0.0-devel - name: keycloak - namespace: test + name: keycloak-web + namespace: zel-test spec: ports: - appProtocol: http @@ -21,14 +27,12 @@ spec: apiVersion: apps/v1 kind: Deployment metadata: - annotations: - custom_annotation: sleep labels: app.kubernetes.io/managed-by: timoni app.kubernetes.io/name: keycloak app.kubernetes.io/version: 0.0.0-devel name: keycloak - namespace: test + namespace: zel-test spec: replicas: 1 selector: @@ -44,6 +48,8 @@ spec: - /opt/keycloak/bin/kc.sh - start env: + - name: KC_CACHE + value: local - name: KC_HEALTH_ENABLED value: "true" - name: KC_HTTP_ENABLED @@ -64,8 +70,6 @@ spec: value: admin - name: KC_DB_PASSWORD value: admin - - name: KC_CACHE - value: local - name: KC_CACHE_STACK value: kubernetes - name: KC_LOG_LEVEL @@ -78,7 +82,6 @@ spec: path: /health port: http scheme: HTTP - initialDelaySeconds: 30 periodSeconds: 30 successThreshold: 1 timeoutSeconds: 10 @@ -98,8 +101,8 @@ spec: timeoutSeconds: 10 resources: requests: - cpu: 10m - memory: 32Mi + cpu: 200m + memory: 768Mi securityContext: allowPrivilegeEscalation: false capabilities: @@ -116,6 +119,7 @@ spec: path: /health port: http scheme: HTTP + initialDelaySeconds: 30 periodSeconds: 15 volumeMounts: [] serviceAccountName: default diff --git a/test/ingress-values.cue b/test/ingress-values.cue new file mode 100644 index 0000000..de643da --- /dev/null +++ b/test/ingress-values.cue @@ -0,0 +1,48 @@ +// Note that this file must have no imports and all values must be concrete. + +// Unsecure Keycloak deployment in http with HA + +@if(!debug) + +package main + +// Defaults +values: { + + image: { + repository: "quay.io/keycloak/keycloak" + digest: "sha256:cff31dc6fbb0ab0b66176b990e6b9e262fa74a501abb9a4bfa4a529cbc8a526a" + tag: "23.0" + } + + ingress: { + ingressClassName: "nginx" + tls: [{ + hosts: ["fake"] + secretName: "auth-tls-secret" + }, + ] + rules: [{ + host: "auth.localtest.me" + http: { + paths: [{ + pathType: "Prefix" + path: "/" + backend: { + service: { + name: "keycloak-web" + port: { + number: 8080 + } + }} + }] + }}] + } + + envs: { + KEYCLOAK_ADMIN_PASSWORD: "admin" + KC_PROXY: "edge" + KC_HOSTNAME_STRICT: false + KC_LOG_LEVEL: "DEBUG" + } +} diff --git a/test/ingress.yaml b/test/ingress.yaml new file mode 100644 index 0000000..d61a3e1 --- /dev/null +++ b/test/ingress.yaml @@ -0,0 +1,146 @@ +apiVersion: v1 +kind: Namespace +metadata: + name: zel-test +--- +apiVersion: v1 +kind: Service +metadata: + labels: + app.kubernetes.io/component: web + app.kubernetes.io/managed-by: timoni + app.kubernetes.io/name: keycloak + app.kubernetes.io/version: 0.0.0-devel + name: keycloak-web + namespace: zel-test +spec: + ports: + - appProtocol: http + name: http + port: 8080 + protocol: TCP + targetPort: http + selector: + app.kubernetes.io/name: keycloak + type: ClusterIP +--- +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + labels: + app.kubernetes.io/managed-by: timoni + app.kubernetes.io/name: keycloak + app.kubernetes.io/version: 0.0.0-devel + name: keycloak + namespace: zel-test +spec: + ingressClassName: nginx + rules: + - host: auth.localtest.me + http: + paths: + - backend: + service: + name: keycloak-web + port: + number: 8080 + path: / + pathType: Prefix + tls: + - hosts: + - fake + secretName: auth-tls-secret +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + app.kubernetes.io/managed-by: timoni + app.kubernetes.io/name: keycloak + app.kubernetes.io/version: 0.0.0-devel + name: keycloak + namespace: zel-test +spec: + replicas: 1 + selector: + matchLabels: + app.kubernetes.io/name: keycloak + template: + metadata: + labels: + app.kubernetes.io/name: keycloak + spec: + containers: + - command: + - /opt/keycloak/bin/kc.sh + - start + env: + - name: KC_CACHE + value: local + - name: KC_HEALTH_ENABLED + value: "true" + - name: KC_HTTP_ENABLED + value: "true" + - name: KC_HOSTNAME_STRICT + value: "false" + - name: KC_PROXY + value: edge + - name: KEYCLOAK_ADMIN + value: admin + - name: KEYCLOAK_ADMIN_PASSWORD + value: admin + - name: KC_CACHE_STACK + value: kubernetes + - name: KC_LOG_LEVEL + value: DEBUG + image: quay.io/keycloak/keycloak:23.0@sha256:cff31dc6fbb0ab0b66176b990e6b9e262fa74a501abb9a4bfa4a529cbc8a526a + imagePullPolicy: IfNotPresent + livenessProbe: + failureThreshold: 3 + httpGet: + path: /health + port: http + scheme: HTTP + periodSeconds: 30 + successThreshold: 1 + timeoutSeconds: 10 + name: keycloak + ports: + - containerPort: 8080 + name: http + protocol: TCP + readinessProbe: + failureThreshold: 3 + httpGet: + path: /health + port: http + scheme: HTTP + periodSeconds: 15 + successThreshold: 1 + timeoutSeconds: 10 + resources: + requests: + cpu: 200m + memory: 768Mi + securityContext: + allowPrivilegeEscalation: false + capabilities: + drop: + - ALL + privileged: false + readOnlyRootFilesystem: false + runAsNonRoot: true + seccompProfile: + type: RuntimeDefault + startupProbe: + failureThreshold: 30 + httpGet: + path: /health + port: http + scheme: HTTP + initialDelaySeconds: 30 + periodSeconds: 15 + volumeMounts: [] + serviceAccountName: default + volumes: [] +--- diff --git a/test/minimum-values.cue b/test/minimum-values.cue index d8702f4..9870fc9 100644 --- a/test/minimum-values.cue +++ b/test/minimum-values.cue @@ -6,6 +6,6 @@ package main values: { envs: { KEYCLOAK_ADMIN_PASSWORD: "admin" - KC_HOSTNAME_STRICT: false + KC_HOSTNAME_STRICT: false } } diff --git a/test/minimum.yaml b/test/minimum.yaml index 1c1c3ac..7f65bf3 100644 --- a/test/minimum.yaml +++ b/test/minimum.yaml @@ -1,11 +1,17 @@ apiVersion: v1 +kind: Namespace +metadata: + name: test +--- +apiVersion: v1 kind: Service metadata: labels: + app.kubernetes.io/component: web app.kubernetes.io/managed-by: timoni app.kubernetes.io/name: keycloak app.kubernetes.io/version: 0.0.0-devel - name: keycloak + name: keycloak-web namespace: test spec: ports: @@ -42,6 +48,8 @@ spec: - /opt/keycloak/bin/kc.sh - start env: + - name: KC_CACHE + value: local - name: KC_HEALTH_ENABLED value: "true" - name: KC_HTTP_ENABLED @@ -52,8 +60,6 @@ spec: value: admin - name: KEYCLOAK_ADMIN_PASSWORD value: admin - - name: KC_CACHE - value: local - name: KC_CACHE_STACK value: kubernetes image: quay.io/keycloak/keycloak:23.0@sha256:cff31dc6fbb0ab0b66176b990e6b9e262fa74a501abb9a4bfa4a529cbc8a526a @@ -64,7 +70,6 @@ spec: path: /health port: http scheme: HTTP - initialDelaySeconds: 30 periodSeconds: 30 successThreshold: 1 timeoutSeconds: 10 @@ -84,8 +89,8 @@ spec: timeoutSeconds: 10 resources: requests: - cpu: 10m - memory: 32Mi + cpu: 200m + memory: 768Mi securityContext: allowPrivilegeEscalation: false capabilities: @@ -102,6 +107,7 @@ spec: path: /health port: http scheme: HTTP + initialDelaySeconds: 30 periodSeconds: 15 volumeMounts: [] serviceAccountName: default diff --git a/test/networkpolicy-values.cue b/test/networkpolicy-values.cue index e059fec..af490c1 100644 --- a/test/networkpolicy-values.cue +++ b/test/networkpolicy-values.cue @@ -7,7 +7,6 @@ values: { envs: { KEYCLOAK_ADMIN_PASSWORD: "admin" } - cacheIspn: true networkPolicyCreate: true networkPolicyRules: [{ from: [{ diff --git a/test/networkpolicy.yaml b/test/networkpolicy.yaml index 4c54147..d4b7c33 100644 --- a/test/networkpolicy.yaml +++ b/test/networkpolicy.yaml @@ -1,11 +1,17 @@ apiVersion: v1 +kind: Namespace +metadata: + name: test +--- +apiVersion: v1 kind: Service metadata: labels: + app.kubernetes.io/component: web app.kubernetes.io/managed-by: timoni app.kubernetes.io/name: keycloak app.kubernetes.io/version: 0.0.0-devel - name: keycloak + name: keycloak-web namespace: test spec: ports: @@ -18,124 +24,6 @@ spec: app.kubernetes.io/name: keycloak type: ClusterIP --- -apiVersion: v1 -kind: Service -metadata: - labels: - app.kubernetes.io/managed-by: timoni - app.kubernetes.io/name: keycloak - app.kubernetes.io/version: 0.0.0-devel - name: keycloak-jgroups - namespace: test -spec: - ports: - - name: jgroups - port: 7800 - protocol: TCP - targetPort: jgroups - selector: - app.kubernetes.io/name: keycloak - type: ClusterIP ---- -apiVersion: v1 -data: - cache-ispn.xml: |2- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -immutable: true -kind: ConfigMap -metadata: - labels: - app.kubernetes.io/managed-by: timoni - app.kubernetes.io/name: keycloak - app.kubernetes.io/version: 0.0.0-devel - name: keycloak-9c00292b - namespace: test ---- apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: @@ -155,11 +43,9 @@ spec: - port: 8080 protocol: TCP - from: - - podSelector: - matchLabels: - app.kubernetes.io/name: keycloak + - podSelector: {} ports: - - port: 7800 + - port: 8080 protocol: TCP podSelector: matchLabels: @@ -191,6 +77,8 @@ spec: - /opt/keycloak/bin/kc.sh - start env: + - name: KC_CACHE + value: local - name: KC_HEALTH_ENABLED value: "true" - name: KC_HTTP_ENABLED @@ -199,14 +87,8 @@ spec: value: admin - name: KEYCLOAK_ADMIN_PASSWORD value: admin - - name: KC_CACHE - value: ispn - - name: KC_CACHE_CONFIG_FILE - value: cache-ispn.xml - name: KC_CACHE_STACK value: kubernetes - - name: JAVA_OPTS_APPEND - value: -Djgroups.dns.query=keycloak-jgroups image: quay.io/keycloak/keycloak:23.0@sha256:cff31dc6fbb0ab0b66176b990e6b9e262fa74a501abb9a4bfa4a529cbc8a526a imagePullPolicy: IfNotPresent livenessProbe: @@ -215,7 +97,6 @@ spec: path: /health port: http scheme: HTTP - initialDelaySeconds: 30 periodSeconds: 30 successThreshold: 1 timeoutSeconds: 10 @@ -224,9 +105,6 @@ spec: - containerPort: 8080 name: http protocol: TCP - - containerPort: 7800 - name: jgroups - protocol: TCP readinessProbe: failureThreshold: 3 httpGet: @@ -238,8 +116,8 @@ spec: timeoutSeconds: 10 resources: requests: - cpu: 10m - memory: 32Mi + cpu: 200m + memory: 768Mi securityContext: allowPrivilegeEscalation: false capabilities: @@ -256,16 +134,9 @@ spec: path: /health port: http scheme: HTTP + initialDelaySeconds: 30 periodSeconds: 15 - volumeMounts: - - mountPath: /opt/keycloak/conf - name: cache + volumeMounts: [] serviceAccountName: default - volumes: - - configMap: - items: - - key: cache-ispn.xml - path: cache-ispn.xml - name: keycloak-9c00292b - name: cache + volumes: [] --- diff --git a/test/pdb-values.cue b/test/pdb-values.cue index b24e6a7..f4f3348 100644 --- a/test/pdb-values.cue +++ b/test/pdb-values.cue @@ -11,13 +11,13 @@ values: { replicas: 4 - pdbSpec: { - minAvailable: 2 + pdb: { + minAvailable: 2 maxUnavailable: 1 } envs: { - KEYCLOAK_ADMIN: "admin" KEYCLOAK_ADMIN_PASSWORD: "admin" + KC_DB: "postgres" } } diff --git a/test/pdb.yaml b/test/pdb.yaml index 3202ab2..03e69e0 100644 --- a/test/pdb.yaml +++ b/test/pdb.yaml @@ -1,11 +1,17 @@ apiVersion: v1 +kind: Namespace +metadata: + name: test +--- +apiVersion: v1 kind: Service metadata: labels: + app.kubernetes.io/component: web app.kubernetes.io/managed-by: timoni app.kubernetes.io/name: keycloak app.kubernetes.io/version: 0.0.0-devel - name: keycloak + name: keycloak-web namespace: test spec: ports: @@ -22,10 +28,11 @@ apiVersion: v1 kind: Service metadata: labels: + app.kubernetes.io/component: jgroup app.kubernetes.io/managed-by: timoni app.kubernetes.io/name: keycloak app.kubernetes.io/version: 0.0.0-devel - name: keycloak-jgroups + name: keycloak-jgroup namespace: test spec: ports: @@ -176,6 +183,14 @@ spec: - /opt/keycloak/bin/kc.sh - start env: + - name: KC_DB + value: postgres + - name: KC_CACHE + value: ispn + - name: JAVA_OPTS_APPEND + value: -Djgroups.dns.query=keycloak-jgroups + - name: KC_CACHE_CONFIG_FILE + value: cache-ispn.xml - name: KC_HEALTH_ENABLED value: "true" - name: KC_HTTP_ENABLED @@ -184,14 +199,8 @@ spec: value: admin - name: KEYCLOAK_ADMIN_PASSWORD value: admin - - name: KC_CACHE - value: ispn - - name: KC_CACHE_CONFIG_FILE - value: cache-ispn.xml - name: KC_CACHE_STACK value: kubernetes - - name: JAVA_OPTS_APPEND - value: -Djgroups.dns.query=keycloak-jgroups image: quay.io/keycloak/keycloak:23.0@sha256:cff31dc6fbb0ab0b66176b990e6b9e262fa74a501abb9a4bfa4a529cbc8a526a imagePullPolicy: IfNotPresent livenessProbe: @@ -200,7 +209,6 @@ spec: path: /health port: http scheme: HTTP - initialDelaySeconds: 30 periodSeconds: 30 successThreshold: 1 timeoutSeconds: 10 @@ -223,8 +231,8 @@ spec: timeoutSeconds: 10 resources: requests: - cpu: 10m - memory: 32Mi + cpu: 200m + memory: 768Mi securityContext: allowPrivilegeEscalation: false capabilities: @@ -241,6 +249,7 @@ spec: path: /health port: http scheme: HTTP + initialDelaySeconds: 30 periodSeconds: 15 volumeMounts: - mountPath: /opt/keycloak/conf diff --git a/test/sa-values.cue b/test/sa-values.cue index b94a76e..414aad8 100644 --- a/test/sa-values.cue +++ b/test/sa-values.cue @@ -14,16 +14,12 @@ values: { digest: "sha256:cff31dc6fbb0ab0b66176b990e6b9e262fa74a501abb9a4bfa4a529cbc8a526a" tag: "23.0" } - metadata: { - annotations: { - root: "root" - } - } - serviceAccountCreate: true serviceAccount: { - metadata: name: "kjj" + metadata: { + name: "kjj" + annotations: {"custom": "test"}} } envs: { diff --git a/test/sa.yaml b/test/sa.yaml index 3f2f0ae..209c0b8 100644 --- a/test/sa.yaml +++ b/test/sa.yaml @@ -1,8 +1,13 @@ apiVersion: v1 +kind: Namespace +metadata: + name: test +--- +apiVersion: v1 kind: ServiceAccount metadata: annotations: - root: root + custom: test labels: app.kubernetes.io/managed-by: timoni app.kubernetes.io/name: keycloak @@ -14,10 +19,11 @@ apiVersion: v1 kind: Service metadata: labels: + app.kubernetes.io/component: web app.kubernetes.io/managed-by: timoni app.kubernetes.io/name: keycloak app.kubernetes.io/version: 0.0.0-devel - name: keycloak + name: keycloak-web namespace: test spec: ports: @@ -33,8 +39,6 @@ spec: apiVersion: apps/v1 kind: Deployment metadata: - annotations: - root: root labels: app.kubernetes.io/managed-by: timoni app.kubernetes.io/name: keycloak @@ -56,6 +60,8 @@ spec: - /opt/keycloak/bin/kc.sh - start env: + - name: KC_CACHE + value: local - name: KC_HEALTH_ENABLED value: "true" - name: KC_HTTP_ENABLED @@ -76,8 +82,6 @@ spec: value: admin - name: KC_DB_PASSWORD value: admin - - name: KC_CACHE - value: local - name: KC_CACHE_STACK value: kubernetes - name: KC_LOG_LEVEL @@ -90,7 +94,6 @@ spec: path: /health port: http scheme: HTTP - initialDelaySeconds: 30 periodSeconds: 30 successThreshold: 1 timeoutSeconds: 10 @@ -110,8 +113,8 @@ spec: timeoutSeconds: 10 resources: requests: - cpu: 10m - memory: 32Mi + cpu: 200m + memory: 768Mi securityContext: allowPrivilegeEscalation: false capabilities: @@ -128,6 +131,7 @@ spec: path: /health port: http scheme: HTTP + initialDelaySeconds: 30 periodSeconds: 15 volumeMounts: [] serviceAccountName: kjj diff --git a/test/test.sh b/test/test.sh index 7f99db2..0164602 100755 --- a/test/test.sh +++ b/test/test.sh @@ -2,14 +2,19 @@ echo "minimum-values" timoni -n test build keycloak ../ --values ../values.cue --values ./minimum-values.cue > ./minimum.yaml echo "http-values" -timoni -n test build keycloak ../ --values ../values.cue --values ./http-values.cue > ./http.yaml +timoni -n zel-test build keycloak ../ --values ../values.cue --values ./http-values.cue > ./http.yaml echo "sa-values" timoni -n test build keycloak ../ --values ../values.cue --values ./sa-values.cue > ./sa.yaml echo "certificate-values" -timoni -n test build keycloak ../ --values ../values.cue --values ./certificate-values.cue > ./certificate.yaml +timoni -n test build keycloak ../ --values ../values.cue --values ./certificate-values.cue > ./certificate.yaml echo "external-secrets-values" timoni -n test build keycloak ../ --values ../values.cue --values ./external-secrets-values.cue > ./external-secrets.yaml echo "pdb-values" timoni -n test build keycloak ../ --values ../values.cue --values ./pdb-values.cue > ./pdb.yaml echo "network-policy-values" timoni -n test build keycloak ../ --values ../values.cue --values ./networkpolicy-values.cue > ./networkpolicy.yaml + +echo "ingress-values" +timoni -n zel-test build keycloak ../ --values ../values.cue --values ./ingress-values.cue > ./ingress.yaml +echo "virtual-service-values" +timoni -n zel-test build keycloak ../ --values ../values.cue --values ./virtualservice-values.cue > ./virtualservice.yaml diff --git a/test/virtualservice-values.cue b/test/virtualservice-values.cue new file mode 100644 index 0000000..c87f83e --- /dev/null +++ b/test/virtualservice-values.cue @@ -0,0 +1,53 @@ +// Note that this file must have no imports and all values must be concrete. + +// Unsecure Keycloak deployment in http with HA + +@if(!debug) + +package main + +// Defaults +values: { + + replicas: 1 + + image: { + repository: "quay.io/keycloak/keycloak" + digest: "sha256:cff31dc6fbb0ab0b66176b990e6b9e262fa74a501abb9a4bfa4a529cbc8a526a" + tag: "23.0" + } + virtualService: { + gateways: [{"istio-system/istio-ingressgateway"}] + hosts: [ + "keycloak.dev.eu.zelros.com", + ] + } + + networkPolicyRules: [{ + from: [{ + namespaceSelector: { + matchLabels: { + "kubernetes.io/metadata.name": "istio-system" + } + } + podSelector: { + matchLabels: { + app: "istio-ingressgateway" + } + } + }, + ] + ports: [{ + protocol: "TCP" + port: 8080 + }, + ]}, + ] + + envs: { + KEYCLOAK_ADMIN_PASSWORD: "admin" + KC_PROXY: "edge" + KC_HOSTNAME_STRICT: false + KC_LOG_LEVEL: "DEBUG" + } +} diff --git a/test/virtualservice.yaml b/test/virtualservice.yaml new file mode 100644 index 0000000..1e02bcc --- /dev/null +++ b/test/virtualservice.yaml @@ -0,0 +1,152 @@ +apiVersion: v1 +kind: Namespace +metadata: + labels: + istio-injection: enabled + name: zel-test +--- +apiVersion: v1 +kind: Service +metadata: + labels: + app.kubernetes.io/component: web + app.kubernetes.io/managed-by: timoni + app.kubernetes.io/name: keycloak + app.kubernetes.io/version: 0.0.0-devel + name: keycloak-web + namespace: zel-test +spec: + ports: + - appProtocol: http + name: http + port: 8080 + protocol: TCP + targetPort: http + selector: + app.kubernetes.io/name: keycloak + type: ClusterIP +--- +apiVersion: networking.istio.io/v1beta1 +kind: VirtualService +metadata: + labels: + app.kubernetes.io/managed-by: timoni + app.kubernetes.io/name: keycloak + app.kubernetes.io/version: 0.0.0-devel + name: keycloak + namespace: zel-test +spec: + gateways: + - istio-system/istio-ingressgateway + hosts: + - keycloak.dev.eu.zelros.com + http: + - directResponse: + status: 403 + match: + - uri: + prefix: /health + - uri: + prefix: /metrics + - match: + - uri: + prefix: / + route: + - destination: + host: keycloak-web + port: + number: 8080 +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + app.kubernetes.io/managed-by: timoni + app.kubernetes.io/name: keycloak + app.kubernetes.io/version: 0.0.0-devel + name: keycloak + namespace: zel-test +spec: + replicas: 1 + selector: + matchLabels: + app.kubernetes.io/name: keycloak + template: + metadata: + labels: + app.kubernetes.io/name: keycloak + spec: + containers: + - command: + - /opt/keycloak/bin/kc.sh + - start + env: + - name: KC_CACHE + value: local + - name: KC_HEALTH_ENABLED + value: "true" + - name: KC_HTTP_ENABLED + value: "true" + - name: KC_HOSTNAME_STRICT + value: "false" + - name: KC_PROXY + value: edge + - name: KEYCLOAK_ADMIN + value: admin + - name: KEYCLOAK_ADMIN_PASSWORD + value: admin + - name: KC_CACHE_STACK + value: kubernetes + - name: KC_LOG_LEVEL + value: DEBUG + image: quay.io/keycloak/keycloak:23.0@sha256:cff31dc6fbb0ab0b66176b990e6b9e262fa74a501abb9a4bfa4a529cbc8a526a + imagePullPolicy: IfNotPresent + livenessProbe: + failureThreshold: 3 + httpGet: + path: /health + port: http + scheme: HTTP + periodSeconds: 30 + successThreshold: 1 + timeoutSeconds: 10 + name: keycloak + ports: + - containerPort: 8080 + name: http + protocol: TCP + readinessProbe: + failureThreshold: 3 + httpGet: + path: /health + port: http + scheme: HTTP + periodSeconds: 15 + successThreshold: 1 + timeoutSeconds: 10 + resources: + requests: + cpu: 200m + memory: 768Mi + securityContext: + allowPrivilegeEscalation: false + capabilities: + drop: + - ALL + privileged: false + readOnlyRootFilesystem: false + runAsNonRoot: true + seccompProfile: + type: RuntimeDefault + startupProbe: + failureThreshold: 30 + httpGet: + path: /health + port: http + scheme: HTTP + initialDelaySeconds: 30 + periodSeconds: 15 + volumeMounts: [] + serviceAccountName: default + volumes: [] +---