diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 3a8a8714..3e2d2565 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -18,7 +18,7 @@ repos: - repo: local hooks: - id: helm-docs - args: [] + args: ["-c", "helm"] description: Uses 'helm-docs' to create documentation from the Helm chart's 'values.yaml' file, and inserts the result into a corresponding 'README.md' file. entry: git-hook/helm-docs.sh language: script diff --git a/.secrets.baseline b/.secrets.baseline index 7e7150c8..2f758ae1 100644 --- a/.secrets.baseline +++ b/.secrets.baseline @@ -3,7 +3,7 @@ "files": "^.secrets.baseline$", "lines": null }, - "generated_at": "2023-11-20T21:39:41Z", + "generated_at": "2024-07-02T16:36:02Z", "plugins_used": [ { "name": "AWSKeyDetector" @@ -136,94 +136,50 @@ } ], "helm/arborist/README.md": [ - { - "hashed_secret": "8a10cd156f8f43ec303f885a7985b1cf90635e23", - "is_secret": false, - "is_verified": false, - "line_number": 32, - "type": "Secret Keyword" - }, - { - "hashed_secret": "2546383b95bb44732e9be6a877fd476c0442fdab", - "is_secret": false, - "is_verified": false, - "line_number": 45, - "type": "Secret Keyword" - }, { "hashed_secret": "d84ce25b0f9bc2cc263006ae39453efb22cc2900", "is_secret": false, "is_verified": false, - "line_number": 47, + "line_number": 55, "type": "Secret Keyword" }, { "hashed_secret": "f09dd6e359833a12f48c4c4255d6e87a6e55cfe9", "is_secret": false, "is_verified": false, - "line_number": 65, + "line_number": 73, "type": "Secret Keyword" } ], "helm/audit/README.md": [ { - "hashed_secret": "8a10cd156f8f43ec303f885a7985b1cf90635e23", - "is_secret": false, - "is_verified": false, - "line_number": 40, - "type": "Secret Keyword" - }, - { - "hashed_secret": "2546383b95bb44732e9be6a877fd476c0442fdab", + "hashed_secret": "a04a85e28ae4f699c0f8d014ad41160c9b9206f0", "is_secret": false, "is_verified": false, - "line_number": 53, + "line_number": 39, "type": "Secret Keyword" }, { "hashed_secret": "d84ce25b0f9bc2cc263006ae39453efb22cc2900", "is_secret": false, "is_verified": false, - "line_number": 55, + "line_number": 65, "type": "Secret Keyword" }, { "hashed_secret": "f09dd6e359833a12f48c4c4255d6e87a6e55cfe9", "is_secret": false, "is_verified": false, - "line_number": 75, - "type": "Secret Keyword" - } - ], - "helm/aws-es-proxy/README.md": [ - { - "hashed_secret": "7c150ec931dbb741d0bfd6c8f4ef914026c0b44b", - "is_secret": false, - "is_verified": false, - "line_number": 61, + "line_number": 85, "type": "Secret Keyword" } ], "helm/common/README.md": [ - { - "hashed_secret": "8a10cd156f8f43ec303f885a7985b1cf90635e23", - "is_secret": false, - "is_verified": false, - "line_number": 11, - "type": "Secret Keyword" - }, - { - "hashed_secret": "2546383b95bb44732e9be6a877fd476c0442fdab", - "is_secret": false, - "is_verified": false, - "line_number": 22, - "type": "Secret Keyword" - }, { "hashed_secret": "d84ce25b0f9bc2cc263006ae39453efb22cc2900", "is_secret": false, "is_verified": false, - "line_number": 24, + "line_number": 25, "type": "Secret Keyword" } ], @@ -248,14 +204,14 @@ "hashed_secret": "b47233f6f28e9716c72d5eba0278edea3a24baad", "is_secret": false, "is_verified": false, - "line_number": 39, + "line_number": 38, "type": "Secret Keyword" }, { "hashed_secret": "3f6d5580af2ddf647ca25346aa6ec9c434577d05", "is_secret": false, "is_verified": false, - "line_number": 55, + "line_number": 54, "type": "Secret Keyword" } ], @@ -264,44 +220,44 @@ "hashed_secret": "afc848c316af1a89d49826c5ae9d00ed769415f3", "is_secret": false, "is_verified": false, - "line_number": 79, + "line_number": 80, "type": "Secret Keyword" } ], "helm/fence/README.md": [ { - "hashed_secret": "49bed5bac5cc06bafd528df89918bf34973861ec", + "hashed_secret": "7f57cb0116aa983d9844a39f6da9244cf98036b1", "is_secret": false, "is_verified": false, - "line_number": 93, + "line_number": 92, "type": "Secret Keyword" }, { - "hashed_secret": "2546383b95bb44732e9be6a877fd476c0442fdab", + "hashed_secret": "b266a6d0f00bb36f6b98134bf4cec71f2d7943a3", "is_secret": false, "is_verified": false, - "line_number": 106, + "line_number": 102, "type": "Secret Keyword" }, { "hashed_secret": "d84ce25b0f9bc2cc263006ae39453efb22cc2900", "is_secret": false, "is_verified": false, - "line_number": 108, + "line_number": 127, "type": "Secret Keyword" }, { "hashed_secret": "f09dd6e359833a12f48c4c4255d6e87a6e55cfe9", "is_secret": false, "is_verified": false, - "line_number": 135, + "line_number": 154, "type": "Secret Keyword" }, { "hashed_secret": "680318f193e2ef208430b002ad07ff98a79ac457", "is_secret": false, "is_verified": false, - "line_number": 185, + "line_number": 200, "type": "Secret Keyword" } ], @@ -365,78 +321,73 @@ "hashed_secret": "5d07e1b80e448a213b392049888111e1779a52db", "is_secret": false, "is_verified": false, - "line_number": 1932, + "line_number": 1963, "type": "Secret Keyword" } ], - "helm/gen3/README.md": [ + "helm/frontend-framework/README.md": [ { - "hashed_secret": "1740c48fa3141d4851b14f97e3bc0f46f7670672", + "hashed_secret": "2546383b95bb44732e9be6a877fd476c0442fdab", "is_secret": false, "is_verified": false, - "line_number": 127, + "line_number": 51, "type": "Secret Keyword" - } - ], - "helm/gen3/values.yaml": [ + }, { - "hashed_secret": "9b5925ea817163740dfb287a9894e8ab3aba2c18", + "hashed_secret": "d84ce25b0f9bc2cc263006ae39453efb22cc2900", "is_secret": false, "is_verified": false, - "line_number": 216, + "line_number": 53, "type": "Secret Keyword" } ], - "helm/guppy/README.md": [ - { - "hashed_secret": "39e819806b607b544fec2ea49fa88a7ab81929ca", - "is_secret": false, - "is_verified": false, - "line_number": 43, - "type": "Secret Keyword" - }, + "helm/gen3/README.md": [ { - "hashed_secret": "2546383b95bb44732e9be6a877fd476c0442fdab", + "hashed_secret": "7422c958ec5a8e5f87c9e81cdf426ef0e193332c", "is_secret": false, "is_verified": false, - "line_number": 60, + "line_number": 83, "type": "Secret Keyword" }, { - "hashed_secret": "d84ce25b0f9bc2cc263006ae39453efb22cc2900", + "hashed_secret": "1740c48fa3141d4851b14f97e3bc0f46f7670672", "is_secret": false, "is_verified": false, - "line_number": 62, + "line_number": 122, "type": "Secret Keyword" } ], - "helm/hatchery/README.md": [ + "helm/gen3/values.yaml": [ { - "hashed_secret": "8a10cd156f8f43ec303f885a7985b1cf90635e23", + "hashed_secret": "9b5925ea817163740dfb287a9894e8ab3aba2c18", "is_secret": false, "is_verified": false, - "line_number": 30, + "line_number": 200, "type": "Secret Keyword" - }, + } + ], + "helm/guppy/README.md": [ { - "hashed_secret": "2546383b95bb44732e9be6a877fd476c0442fdab", + "hashed_secret": "d84ce25b0f9bc2cc263006ae39453efb22cc2900", "is_secret": false, "is_verified": false, - "line_number": 47, + "line_number": 61, "type": "Secret Keyword" - }, + } + ], + "helm/hatchery/README.md": [ { "hashed_secret": "d84ce25b0f9bc2cc263006ae39453efb22cc2900", "is_secret": false, "is_verified": false, - "line_number": 49, + "line_number": 48, "type": "Secret Keyword" }, { "hashed_secret": "e94cc2a86b04ad4ddc98fcbf91ed236437939d47", "is_secret": false, "is_verified": false, - "line_number": 57, + "line_number": 56, "type": "Secret Keyword" } ], @@ -445,44 +396,37 @@ "hashed_secret": "9b5925ea817163740dfb287a9894e8ab3aba2c18", "is_secret": false, "is_verified": false, - "line_number": 186, + "line_number": 189, "type": "Secret Keyword" } ], "helm/indexd/README.md": [ { - "hashed_secret": "0d5cd5f3caaaf8354a6c62816b97bcae006d4bcf", - "is_secret": false, - "is_verified": false, - "line_number": 31, - "type": "Secret Keyword" - }, - { - "hashed_secret": "2546383b95bb44732e9be6a877fd476c0442fdab", + "hashed_secret": "167402961a8c8a8b3764e865e865efa9ada95369", "is_secret": false, "is_verified": false, - "line_number": 48, + "line_number": 30, "type": "Secret Keyword" }, { "hashed_secret": "d84ce25b0f9bc2cc263006ae39453efb22cc2900", "is_secret": false, "is_verified": false, - "line_number": 50, + "line_number": 55, "type": "Secret Keyword" }, { "hashed_secret": "f09dd6e359833a12f48c4c4255d6e87a6e55cfe9", "is_secret": false, "is_verified": false, - "line_number": 69, + "line_number": 74, "type": "Secret Keyword" }, { "hashed_secret": "44cb746036385723dde2ac36e53da8932a69bfe2", "is_secret": false, "is_verified": false, - "line_number": 104, + "line_number": 108, "type": "Secret Keyword" } ], @@ -497,86 +441,72 @@ ], "helm/manifestservice/README.md": [ { - "hashed_secret": "3231d1a39e7956e9e5e7b59c5f3bef462f71333c", + "hashed_secret": "cc524de4657898e872ff46e0a9256f4e186cdfe6", "is_secret": false, "is_verified": false, - "line_number": 78, + "line_number": 36, + "type": "Secret Keyword" + }, + { + "hashed_secret": "611f2e9064b518afdb23f201321f39029dd28917", + "is_secret": false, + "is_verified": false, + "line_number": 86, "type": "Secret Keyword" } ], - "helm/manifestservice/templates/metadataservice-creds.yaml": [ + "helm/manifestservice/templates/manifestservice-creds.yaml": [ { "hashed_secret": "d2e2ab0f407e4ee3cf2ab87d61c31b25a74085e5", "is_secret": false, "is_verified": false, - "line_number": 12, + "line_number": 13, "type": "Secret Keyword" } ], "helm/metadata/README.md": [ { - "hashed_secret": "8a10cd156f8f43ec303f885a7985b1cf90635e23", + "hashed_secret": "cbdb7939a61698c9c866ea614399ef7eb7770c68", "is_secret": false, "is_verified": false, "line_number": 49, "type": "Secret Keyword" }, - { - "hashed_secret": "2546383b95bb44732e9be6a877fd476c0442fdab", - "is_secret": false, - "is_verified": false, - "line_number": 66, - "type": "Secret Keyword" - }, { "hashed_secret": "d84ce25b0f9bc2cc263006ae39453efb22cc2900", "is_secret": false, "is_verified": false, - "line_number": 68, + "line_number": 74, "type": "Secret Keyword" }, { "hashed_secret": "f09dd6e359833a12f48c4c4255d6e87a6e55cfe9", "is_secret": false, "is_verified": false, - "line_number": 87, + "line_number": 93, "type": "Secret Keyword" } ], "helm/peregrine/README.md": [ - { - "hashed_secret": "4e7b6794afbe3027589b92744144f18a3920b115", - "is_secret": false, - "is_verified": false, - "line_number": 32, - "type": "Secret Keyword" - }, - { - "hashed_secret": "2546383b95bb44732e9be6a877fd476c0442fdab", - "is_secret": false, - "is_verified": false, - "line_number": 49, - "type": "Secret Keyword" - }, { "hashed_secret": "d84ce25b0f9bc2cc263006ae39453efb22cc2900", "is_secret": false, "is_verified": false, - "line_number": 51, + "line_number": 55, "type": "Secret Keyword" }, { "hashed_secret": "f09dd6e359833a12f48c4c4255d6e87a6e55cfe9", "is_secret": false, "is_verified": false, - "line_number": 67, + "line_number": 71, "type": "Secret Keyword" }, { "hashed_secret": "489e396b7c68f95c6018f7b98ef7b1b94587ef29", "is_secret": false, "is_verified": false, - "line_number": 100, + "line_number": 103, "type": "Secret Keyword" } ], @@ -599,32 +529,18 @@ } ], "helm/pidgin/README.md": [ - { - "hashed_secret": "8a10cd156f8f43ec303f885a7985b1cf90635e23", - "is_secret": false, - "is_verified": false, - "line_number": 36, - "type": "Secret Keyword" - }, - { - "hashed_secret": "2546383b95bb44732e9be6a877fd476c0442fdab", - "is_secret": false, - "is_verified": false, - "line_number": 53, - "type": "Secret Keyword" - }, { "hashed_secret": "d84ce25b0f9bc2cc263006ae39453efb22cc2900", "is_secret": false, "is_verified": false, - "line_number": 55, + "line_number": 54, "type": "Secret Keyword" }, { "hashed_secret": "abb751db44bcfd1bb9d4ad53e40138422abd739e", "is_secret": false, "is_verified": false, - "line_number": 67, + "line_number": 66, "type": "Secret Keyword" } ], @@ -633,35 +549,21 @@ "hashed_secret": "eb9739c6625f06b4ab73035223366dda6262ae77", "is_secret": false, "is_verified": false, - "line_number": 37, + "line_number": 38, "type": "Base64 High Entropy String" }, { "hashed_secret": "08eeb737b239bdb7362a875b90e22c10b8826b20", "is_secret": false, "is_verified": false, - "line_number": 41, - "type": "Base64 High Entropy String" - }, - { - "hashed_secret": "0d5cd5f3caaaf8354a6c62816b97bcae006d4bcf", - "is_secret": false, - "is_verified": false, "line_number": 42, - "type": "Secret Keyword" - }, - { - "hashed_secret": "2546383b95bb44732e9be6a877fd476c0442fdab", - "is_secret": false, - "is_verified": false, - "line_number": 59, - "type": "Secret Keyword" + "type": "Base64 High Entropy String" }, { "hashed_secret": "d84ce25b0f9bc2cc263006ae39453efb22cc2900", "is_secret": false, "is_verified": false, - "line_number": 61, + "line_number": 62, "type": "Secret Keyword" } ], @@ -669,66 +571,45 @@ { "hashed_secret": "08eeb737b239bdb7362a875b90e22c10b8826b20", "is_verified": false, - "line_number": 469, + "line_number": 480, "type": "Base64 High Entropy String" }, { "hashed_secret": "eb9739c6625f06b4ab73035223366dda6262ae77", "is_verified": false, - "line_number": 472, + "line_number": 483, "type": "Base64 High Entropy String" } ], "helm/requestor/README.md": [ - { - "hashed_secret": "2546383b95bb44732e9be6a877fd476c0442fdab", - "is_secret": false, - "is_verified": false, - "line_number": 58, - "type": "Secret Keyword" - }, { "hashed_secret": "d84ce25b0f9bc2cc263006ae39453efb22cc2900", "is_secret": false, "is_verified": false, - "line_number": 60, + "line_number": 64, "type": "Secret Keyword" }, { "hashed_secret": "f09dd6e359833a12f48c4c4255d6e87a6e55cfe9", "is_secret": false, "is_verified": false, - "line_number": 83, + "line_number": 87, "type": "Secret Keyword" } ], "helm/revproxy/README.md": [ - { - "hashed_secret": "5f0d5766b5954edbce68e73920428d26b9a293c8", - "is_secret": false, - "is_verified": false, - "line_number": 29, - "type": "Secret Keyword" - }, - { - "hashed_secret": "2546383b95bb44732e9be6a877fd476c0442fdab", - "is_secret": false, - "is_verified": false, - "line_number": 46, - "type": "Secret Keyword" - }, { "hashed_secret": "d84ce25b0f9bc2cc263006ae39453efb22cc2900", "is_secret": false, "is_verified": false, - "line_number": 48, + "line_number": 50, "type": "Secret Keyword" }, { "hashed_secret": "abb751db44bcfd1bb9d4ad53e40138422abd739e", "is_secret": false, "is_verified": false, - "line_number": 73, + "line_number": 77, "type": "Secret Keyword" } ], @@ -742,53 +623,18 @@ } ], "helm/sheepdog/README.md": [ - { - "hashed_secret": "8a10cd156f8f43ec303f885a7985b1cf90635e23", - "is_secret": false, - "is_verified": false, - "line_number": 41, - "type": "Secret Keyword" - }, - { - "hashed_secret": "2546383b95bb44732e9be6a877fd476c0442fdab", - "is_secret": false, - "is_verified": false, - "line_number": 58, - "type": "Secret Keyword" - }, { "hashed_secret": "d84ce25b0f9bc2cc263006ae39453efb22cc2900", "is_secret": false, "is_verified": false, - "line_number": 60, + "line_number": 64, "type": "Secret Keyword" }, { "hashed_secret": "f09dd6e359833a12f48c4c4255d6e87a6e55cfe9", "is_secret": false, "is_verified": false, - "line_number": 75, - "type": "Secret Keyword" - }, - { - "hashed_secret": "c2c4e52c03a03ce3efeb21eb202d301018d4548e", - "is_secret": false, - "is_verified": false, - "line_number": 96, - "type": "Secret Keyword" - }, - { - "hashed_secret": "afc848c316af1a89d49826c5ae9d00ed769415f3", - "is_secret": false, - "is_verified": false, - "line_number": 103, - "type": "Secret Keyword" - }, - { - "hashed_secret": "fa4497447699cdb0a81c66a7f21af28a75170195", - "is_secret": false, - "is_verified": false, - "line_number": 105, + "line_number": 79, "type": "Secret Keyword" } ], @@ -801,7 +647,7 @@ "type": "Basic Auth Credentials" } ], - "helm/sheepdog/sheepdog-secret/wsgi.py": [ + "helm/sheepdog/sheepdog-secret/settings.py": [ { "hashed_secret": "347cd9c53ff77d41a7b22aa56c7b4efaf54658e3", "is_secret": false, @@ -810,35 +656,19 @@ "type": "Basic Auth Credentials" } ], - "helm/sheepdog/values.yaml": [ - { - "hashed_secret": "afc848c316af1a89d49826c5ae9d00ed769415f3", - "is_secret": false, - "is_verified": false, - "line_number": 242, - "type": "Secret Keyword" - } - ], "helm/sower/README.md": [ { - "hashed_secret": "8a10cd156f8f43ec303f885a7985b1cf90635e23", - "is_secret": false, - "is_verified": false, - "line_number": 36, - "type": "Secret Keyword" - }, - { - "hashed_secret": "2546383b95bb44732e9be6a877fd476c0442fdab", + "hashed_secret": "3d4368cd822c4a36144c2bcc8cb8e90b63c7e5fe", "is_secret": false, "is_verified": false, - "line_number": 51, + "line_number": 34, "type": "Secret Keyword" }, { "hashed_secret": "d84ce25b0f9bc2cc263006ae39453efb22cc2900", "is_secret": false, "is_verified": false, - "line_number": 53, + "line_number": 58, "type": "Secret Keyword" } ], @@ -847,37 +677,23 @@ "hashed_secret": "d2e2ab0f407e4ee3cf2ab87d61c31b25a74085e5", "is_secret": false, "is_verified": false, - "line_number": 13, + "line_number": 14, "type": "Secret Keyword" } ], "helm/ssjdispatcher/README.md": [ - { - "hashed_secret": "8a10cd156f8f43ec303f885a7985b1cf90635e23", - "is_secret": false, - "is_verified": false, - "line_number": 40, - "type": "Secret Keyword" - }, - { - "hashed_secret": "2546383b95bb44732e9be6a877fd476c0442fdab", - "is_secret": false, - "is_verified": false, - "line_number": 57, - "type": "Secret Keyword" - }, { "hashed_secret": "d84ce25b0f9bc2cc263006ae39453efb22cc2900", "is_secret": false, "is_verified": false, - "line_number": 59, + "line_number": 58, "type": "Secret Keyword" }, { "hashed_secret": "0c86d58792b32e1d12af733a0614837ff9002014", "is_secret": false, "is_verified": false, - "line_number": 114, + "line_number": 113, "type": "Secret Keyword" } ], @@ -895,37 +711,23 @@ "hashed_secret": "13d9ed7e3d69f1b6330dff80bc4658931708eddc", "is_secret": false, "is_verified": false, - "line_number": 215, + "line_number": 218, "type": "Secret Keyword" } ], "helm/wts/README.md": [ - { - "hashed_secret": "8a10cd156f8f43ec303f885a7985b1cf90635e23", - "is_secret": false, - "is_verified": false, - "line_number": 30, - "type": "Secret Keyword" - }, - { - "hashed_secret": "2546383b95bb44732e9be6a877fd476c0442fdab", - "is_secret": false, - "is_verified": false, - "line_number": 47, - "type": "Secret Keyword" - }, { "hashed_secret": "d84ce25b0f9bc2cc263006ae39453efb22cc2900", "is_secret": false, "is_verified": false, - "line_number": 49, + "line_number": 53, "type": "Secret Keyword" }, { "hashed_secret": "f09dd6e359833a12f48c4c4255d6e87a6e55cfe9", "is_secret": false, "is_verified": false, - "line_number": 70, + "line_number": 74, "type": "Secret Keyword" } ], diff --git a/README.md b/README.md index 5a63cef1..364a65d7 100644 --- a/README.md +++ b/README.md @@ -117,8 +117,19 @@ NOTE: Gen3 helm charts are currently not used in production by CTDS, but we are For local development you must be connected to a kubernetes cluster. As referenced above in the section `Kubernetes cluster` we recommend using [Rancher Desktop](https://rancherdesktop.io/) as Kubernetes on your local machine, especially on M1 Mac's. You also get ingress and other benefits out of the box. +For MacOS users, [Minikube](https://minikube.sigs.k8s.io/docs/start/) equipped with the ingress addon serves as a viable alternative to Rancher Desktop. On Linux, we've observed that using [Kind](https://kind.sigs.k8s.io/) with an NGINX ingress installed often provides a more seamless experience compared to both Rancher Desktop and Minikube. Essentially, Helm requires access to a Kubernetes cluster with ingress capabilities, facilitating the loading of the portal in your browser for an optimal development workflow. + +To install the NGINX ingress: +``` + helm repo add nginx-stable https://helm.nginx.com/stable + helm repo update + kubectl create ns nginx-ingress + helm install nginx-ingress nginx-stable/nginx-ingress --namespace nginx-ingress +``` + > **Warning** > If you are using Rancher Desktop you need to increase the vm.max_map_count as outlined [here](https://docs.rancherdesktop.io/how-to-guides/increasing-open-file-limit/) +> If you are using Minikube you will need to enabled the ingress addon as outlined [here](https://kubernetes.io/docs/tasks/access-application-cluster/ingress-minikube/) 1. Clone the repository 2. Navigate to the `gen3-helm/helm/gen3` directory and run `helm dependency update` diff --git a/docs/PRODUCTION.md b/docs/PRODUCTION.md index 01b85073..c15bd388 100644 --- a/docs/PRODUCTION.md +++ b/docs/PRODUCTION.md @@ -13,3 +13,14 @@ The postgres and helm charts are included as conditionals in the Gen3 [umbrella repository: "https://charts.bitnami.com/bitnami" condition: global.dev ``` + +### Kubernetes Configmap and Secret Configuration +For the seamless operation of our services, we utilize Kubernetes secrets. To streamline the integration and management of these secrets, we highly recommend deploying External Secret Manager alongside any existing secret management systems you may already have in place. For a comprehensive guide and best practices on implementing External Secrets within our ecosystem, please consult our dedicated External Secrets Documentation available [here](https://github.com/uc-cdis/gen3-helm/blob/master/docs/external_secrets.md). + +Our services also utilize non-secret configuration variables provided via Kubernetes ConfigMaps. For streamlined management, we advise keeping your values.yaml and configuration files files in source control and utilizing ArgoCD for automatic updates and efficient management of your Gen3 Helm chart. + +Each service is designed to seamlessly integrate and manage the combination of Kubernetes secrets and ConfigMaps, ensuring the encapsulated information is effectively injected into the underlying application. + +Please see the diagram provided that details how External Secrets operates. We also mention the use of Argo CD as our choice option for Helm deployments. +![External Secrets Diagram](./images/lucidChart.png "Helm Secrets Manager") + diff --git a/docs/external_secrets.md b/docs/external_secrets.md new file mode 100644 index 00000000..cf4dd5ca --- /dev/null +++ b/docs/external_secrets.md @@ -0,0 +1,179 @@ +# External Secrets Operator + + "External Secrets Operator" is a tool that was created by the Kubernetes community to manage external secrets in a Kubernetes cluster. It allows you to fetch and sync external secret values from various external secret management systems into Kubernetes secrets. One of the external secret management systems it can connect to is AWS Secrets Manager. AWS Secrets Manager allows for the secure storing of your secrets as well as the ability to periodically and automatically rotate your secrets. + +This document will guide you through setting up the essential resources to access your secrets in AWS Secrets Manager and download the External Secrets Operator Helm chart. This way, you can effectively utilize your stored secrets with Helm. + +## Download External Secrets Operator and Create Resources in AWS. +You can use the following Bash script to apply the External Secrets Operator to your cluster and create the necessary AWS resources. Fill in the variables below to get started: + +***Notice: +The Gen3 Helm chart has various jobs and uses for an IAM user. To enhance code reusability, we've implemented the option for jobs and services to share the same AWS IAM global user. If you would like to use the same IAM user for External Secrets and jobs like ["Fence Usersync"](fence_usersync_job.md) or our "AWS ES Proxy Service", you can follow [THIS](global_IAM_helm_user.md) guide that details how to setup a Helm global user. In case you opt for a global IAM user, please comment out the "create_iam_policy" and "create_iam_user" functions at the end of the script.*** + +``` +#!/bin/bash + +AWS_ACCOUNT="" +region="us-east-1" +iam_policy="external_secrets_policy" +iam_user="external_secrets_user" + +helm_install() +{ + echo "# ------------------ Install external-secrets via helm --------------------------#" + helm repo add external-secrets https://charts.external-secrets.io + helm install external-secrets \ + external-secrets/external-secrets \ + -n external-secrets \ + --create-namespace \ + --set installCRDs=true +} + +create_iam_policy() +{ + echo "# ------------------ create iam policy for aws secrets manager --------------------------#" + POLICY_ARN=$(aws iam create-policy --policy-name $iam_policy --policy-document '{ + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Action": [ + "secretsmanager:ListSecrets", + "secretsmanager:GetSecretValue" + ], + "Resource": [ + "*" + ] + } + ] + }') + + iam_policy_arn=$(aws iam list-policies --query "Policies[?PolicyName=='$iam_policy'].Arn" --output text) + echo "Policy Arn: $iam_policy_arn" + # return $iam_policy_arn +} + +create_iam_user() +{ + echo "# ------------------ create user $iam_user --------------------------#" + aws iam create-user --user-name $iam_user + + echo "# ------------------ add iam user $iam_user to policy $iam_policy --------------------------#" + aws iam attach-user-policy --user-name $iam_user --policy-arn $iam_policy_arn + echo "aws iam attach-user-policy --user-name $iam_user --policy-arn $iam_policy_arn" + + echo "# ------------------ create access key and secret key for external-secrets --------------------------#" + aws iam create-access-key --user-name $iam_user > keys.json + access_key=$(jq -r .AccessKey.AccessKeyId keys.json) + secret_key=$(jq -r .AccessKey.SecretAccessKey keys.json) + kubectl create secret generic "$iam_user"-secret --from-literal=access-key=$access_key --from-literal=secret-access-key=$secret_key + rm keys.json +} + +helm_install +#comment out the below if using global iam user. +create_iam_policy +create_iam_user +``` + +***Please note that Terraform for the creation and population of Gen3 Secrets in AWS Secrets Manager is in development currently. This Terraform will also create the Iam user and policies necessary to access these secrets.*** + +## Enabling External Secrets in Helm charts +Our Helm architecture includes a comprehensive [umbrella](https://github.com/uc-cdis/gen3-helm/tree/master/helm/gen) chart designed to streamline the deployment of external secrets across both the umbrella chart itself and its associated subcharts. By configuring the `.Values.global.externalSecrets.deploy` setting within this umbrella chart, users can effortlessly initiate the deployment of all related external secret resources. This includes the external secret resources within the subcharts and the secret store required for their management. + +#### Global Deployment of External Secrets +Upon deployment of the umbrella chart, the `.Values.global.externalSecrets.deploy` setting automatically provisions external secret resources for every subchart. This occurs regardless of the individual external secrets deployment settings within subcharts, even if they are explicitly set to `false`. This feature ensures a unified approach to secret management across all components of the architecture. + +#### Selective Secret Management +For users requiring a more selective application of external secrets — targeting specific secrets while excluding others — the system is designed to accommodate such scenarios with ease. + +External secret resources will only attempt to replace Kubernetes secrets when a corresponding secret is successfully located within the Secrets Manager. In instances where a specific secret is not found, the External Secrets resource will indicate a `SecretSyncedError`, signaling the absence of the targeted resource within the Secrets Manager. This error is acceptable and helpful for users who want to enable the use of AWS Secrets Manager for some, but not all the secrets in a specific Helm chart. + +However, if you wish to utilize External Secrets for managing non-database secrets while still automating the creation of your database secrets, you can configure this behavior explicitly. Set `.Values.global.externalSecrets.dbCreate` to true alongside `.Values.global.postgres.dbCreate` or `.Values.postgres.dbCreate` to initiate the database creation job. This configuration will result in the creation of the necessary databases with their credentials stored securely within Kubernetes Secrets. Subsequently, you also choose to create Secrets in Secrets manager with the values that were generated from the dbCreate job if you wish to store these credentials long term. + +By default, the following services will not create the Helm internal secrets when Secrets Manager is enabled: +- Audit +- Fence +- Indexd +- Manifestservice +- Metadata + +This is because CD tools like Argocd will have trouble syncing resources if the K8s secret was generated via Helm and External Secrets continues to override it. You can configure Helm to still create these secrets with External Secrets enabled by setting the appropriate variable to true. + +For example, to ensure the "audit-g3auto" secret is still created by Helm, you would need to set the following in your values.yaml file: +``` +audit: + # -- (map) External Secrets settings. + externalSecrets: + # -- (string) Will create the Helm "audit-g3auto" secret even if Secrets Manager is enabled. This is helpful if you are wanting to use External Secrets for some, but not all secrets. + createK8sAuditSecret: true +``` + +#### Independent Subchart Deployment +In scenarios where subcharts are deployed independently, outside the scope of the umbrella chart, it is crucial to set the `.Values.global.externalSecrets.deploy` directive within the `values.yaml` file for each specific service. + +Additionally, to facilitate the creation of a Secret Store capable of authenticating with AWS Secrets Manager, the `.Values.global.externalSecrets.separateSecretStore` should be set to true in the relevant charts. This configuration is essential for establishing proper authentication mechanisms for secret retrieval. + +#### Configuring Separate Secret Stores +The `.Values.global.externalSecrets.separateSecretStore` setting can also be applied within the context of the umbrella chart deployment. Utilizing this setting allows for the creation of distinct Secret Stores dedicated to individual services. This approach is particularly beneficial for environments where it is preferable to limit access to Secrets Manager, ensuring that services only have access to the secrets explicitly required for their operation. + +## Helm IAM User +If you are using a separate IAM user for AWS Secrets Manager please follow the below instructions: + +This script Bash script at the beginning of this document should have created a secret titled "NameofIAMuser-user-secret" in your cluster. You will need to retrieve these values to input into your Helm chart for the Secret Store to authenticate with AWS Secrets Manager. + + +Access Key: +``` +kubectl get secret "your secret name" -o jsonpath="{.data.access-key}" | base64 --decode +``` + + +Secret Access Key: +``` +kubectl get secret "your secret name" -o jsonpath="{.data.secret-access-key}" | base64 --decode +``` + +You can paste the IAM access key and secret access key in the `.Values.secrets.awsAccessKeyId`/`.Values.secrets.awsSecretAccessKey` fields in the values.yaml file for the chart(s) you would like to use external secrets for. + +If you are deploying external secrets with the Gen3 umbrella chart, you can utilize a local secret to avoid pasting credentials in the values.yaml file. Just set `.global.aws.useLocalSecret.enabled` to true and supply your secret name. + +Please note that only some Helm charts are compatible with External Secrets currently. We hope to expand this functionality in the future. If a chart is able to use External Secrets, you can see a `.Values.externalSecrets` section in the values.yaml file. + +## How External Secrets Works. +External Secrets relies on three main resources to function properly. (The below have links to examples of each resource) +1. [Aws-config](https://github.com/uc-cdis/gen3-helm/blob/master/helm/common/templates/_aws_config.tpl)- Contains Access and Secret Access keys used by the Cluster Secret Store to authenticate with AWS Secrets Manager +2. [Secret Store](https://github.com/uc-cdis/gen3-helm/blob/master/helm/common/templates/_external_secrets.tpl#L41-L62)- Resource to Authenticate with AWS Secrets Manager +3. [External Secret](https://github.com/uc-cdis/gen3-helm/blob/master/helm/common/templates/_external_secrets.tpl#L15-L38)- References the Secret Store and is used as a "map" to tell External Secrets Operator what secret to grab from External Secrets and the name of the Kubernetes Secret to create locally. + + Anatomy of an ExternalSecret: + ``` + apiVersion: external-secrets.io/v1beta1 + kind: ExternalSecret + metadata: + # Name of the External Secret resource + name: audit-g3auto + spec: + #How often to Sync with AWS Secrets Manager + refreshInterval: 5m + secretStoreRef: + # The name of the Secret Store to use. + name: {{include "cluster-secret-store" .}} + kind: SecretStore + target: + # What Kubernetes secret to create from the secret pulled from AWS Secrets Manager. + name: audit-g3auto + creationPolicy: Owner + data: + # the key inside the new Kubernetes secret + - secretKey: audit-service-config.yaml + remoteRef: + #name of secret in AWS Secrets Manager + key: {{include "audit-g3auto" .}} + ``` + +## Customizing the AWS Secrets Manager Secrets Name. +When pulling a secret from AWS Secrets Manager, you want to ensure that the External Secret resource is referencing the proper name of the secret in AWS Secrets Manager. +You can customize the name of the secret to pull from in the `.Values.externalSecrets` section of a Chart. You can see the name for the confiugrable secrets in a chart by looking in this section as well. + +Any string you put in this section will override the name of the secret that is pulled from AWS Secrets Manager NOT the name of the Kubernetes secret that is created from the External Secret resource. diff --git a/docs/fence_usersync_job.md b/docs/fence_usersync_job.md index a05ed7d6..214ebebc 100644 --- a/docs/fence_usersync_job.md +++ b/docs/fence_usersync_job.md @@ -15,7 +15,12 @@ User lists can be synced from three sources: # S3 user.yaml Setup {#s3-setup} Please see [this](https://github.com/uc-cdis/fence/blob/master/docs/user.yaml_guide.md) documentation that details user.yaml formatting. -You can pull this file from an S3 bucket that is set in the `.Values.usersync.userYamlS3Path` field. Then input the iam credentials for a user that has read access to the specified S3 bucket in the `.Values.usersync.secrets.awsAccessKeyId` and `.Values.usersync.secrets.awsSecretAccessKey` fields. +You can pull this file from an S3 bucket that is set in the `.Values.usersync.userYamlS3Path` field. Then input the IAM credentials for a user that has read access to the specified S3 bucket in the `.Values.secrets.awsAccessKeyId` and `.Values.secrets.awsSecretAccessKey` fields. + +You can utilize a local secret to avoid pasting credentials in the values.yaml file. Just set `.global.aws.useLocalSecret.enabled` to true and supply your secret name. + +***Notice: +The Gen3 Helm chart has various jobs and uses for an IAM user. To enhance code reusability, we've implemented the option for jobs and services to share the same AWS IAM global user. If you would like to use the same IAM user for Fence Usersync, External Secrets, etc.- you can follow [THIS](global_iam_helm_user.md) guide that details how to setup a Helm global user.*** As previously mentioned, if the `.Values.usersync.userYamlS3Path` string is set to "none", the user.yaml file from Fence values.yaml will be used. @@ -59,7 +64,7 @@ For an example of a dbGap auth file (csv), please see [this](https://github.com/ -# Other Customizations +## Other Customizations The `.Values.usersync.schedule` option can be set to customize the cron schedule expression. The default setting is to have the job run once every 30 minutes. The `.Values.usersync.custom_image` can be set to override the default "awshelper" image for the init container of the userync cronjob. \ No newline at end of file diff --git a/docs/global_iam_helm_user.md b/docs/global_iam_helm_user.md new file mode 100644 index 00000000..e2a35d9c --- /dev/null +++ b/docs/global_iam_helm_user.md @@ -0,0 +1,55 @@ +# AWS IAM Global User + +For Helm code reusability, we have added the functionality to use one IAM user for various jobs/services. + +We are currently in the process of integrating this user into our Terraform code. In the meantime, you can manually create a global user by referring to this guide. + +## What this user can do in Helm +- Fence Usersync Job +- ES Index Restore +- Restore PGdump +- External Secrets +- AWS ES Proxy Service + + + +Example policy containing all the proper permissions: +``` +{ + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Action": "s3:GetObject", + "Resource": [ + "arn:aws:s3:::$BUCKET/$ENVIRONMENT/*", + # Fence Usersync Job: Name of the userYamlS3Path containing the user.yaml file + "arn:aws:s3:::$BUCKET/$ENVIRONMENT/$VERSION/elasticsearch/*", + # ES Index Restore Job: Name of the dbRestoreBucket with the proper path to the ES dump files. + "arn:aws:s3:::$BUCKET/$ENVIRONMENT/$VERSION/pgdumps/*" + # DB PG Dump Restore Job: Name of the dbRestoreBucket with the proper path to the SQL dump files. + ] + }, + { + "Effect": "Allow", + "Action": [ + "secretsmanager:ListSecrets", + "secretsmanager:GetSecretValue" + ], + "Resource": [ + "*" + # External Secrets: Leave as is to allow External Secrets access to your secrets in Secrets Manager. + ] + }, + { + "Effect": "Allow", + "Action": "es:*", + "Resource": "arn:aws:es:REGION:ACCOUNT_ID:domain/CLUSTER_NAME/*" + # AWS ES Proxy Service: Arn of your Elasticsearch Cluster in AWS. + } + ] +} +``` + +## After Creating the User +In order to integrate the user in Helm, paste in the values of your Access and Secret Access key in `.Values.global.aws.awsAccessKeyId` and `.Values.global.aws.awsSecretAccessKey` \ No newline at end of file diff --git a/docs/images/lucidChart.png b/docs/images/lucidChart.png new file mode 100644 index 00000000..dbb986c4 Binary files /dev/null and b/docs/images/lucidChart.png differ diff --git a/helm/ambassador/Chart.yaml b/helm/ambassador/Chart.yaml index b4e745d5..b525c4d0 100644 --- a/helm/ambassador/Chart.yaml +++ b/helm/ambassador/Chart.yaml @@ -15,7 +15,7 @@ type: application # This is the chart version. This version number should be incremented each time you make changes # to the chart and its templates, including the app version. # Versions are expected to follow Semantic Versioning (https://semver.org/) -version: 0.1.9 +version: 0.1.11 # This is the version number of the application being deployed. This version number should be # incremented each time you make changes to the application. Versions are not expected to @@ -25,5 +25,5 @@ appVersion: "1.4.2" dependencies: - name: common - version: 0.1.8 + version: 0.1.10 repository: file://../common diff --git a/helm/ambassador/README.md b/helm/ambassador/README.md index 06e4b0e2..2e684849 100644 --- a/helm/ambassador/README.md +++ b/helm/ambassador/README.md @@ -1,6 +1,6 @@ # ambassador -![Version: 0.1.9](https://img.shields.io/badge/Version-0.1.9-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: 1.4.2](https://img.shields.io/badge/AppVersion-1.4.2-informational?style=flat-square) +![Version: 0.1.11](https://img.shields.io/badge/Version-0.1.11-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: 1.4.2](https://img.shields.io/badge/AppVersion-1.4.2-informational?style=flat-square) A Helm chart for deploying ambassador for gen3 @@ -8,7 +8,7 @@ A Helm chart for deploying ambassador for gen3 | Repository | Name | Version | |------------|------|---------| -| file://../common | common | 0.1.8 | +| file://../common | common | 0.1.10 | ## Values @@ -26,7 +26,6 @@ A Helm chart for deploying ambassador for gen3 | datadogProfilingEnabled | bool | `true` | If enabled, the Datadog Agent will collect profiling data for your application using the Continuous Profiler. This data can be used to identify performance bottlenecks and optimize your application. | | datadogTraceSampleRate | int | `1` | A value between 0 and 1, that represents the percentage of requests that will be traced. For example, a value of 0.5 means that 50% of requests will be traced. | | fullnameOverride | string | `"ambassador-deployment"` | Override the full name of the deployment. | -| global | map | `{"ddEnabled":false,"environment":"default","minAvialable":1,"pdb":false}` | Global configuration options. | | global.ddEnabled | bool | `false` | Whether Datadog is enabled. | | global.environment | string | `"default"` | Environment name. This should be the same as vpcname if you're doing an AWS deployment. Currently this is being used to share ALB's if you have multiple namespaces. Might be used other places too. | | global.minAvialable | int | `1` | The minimum amount of pods that are available at all times if the PDB is deployed. | @@ -61,5 +60,3 @@ A Helm chart for deploying ambassador for gen3 | tolerations | list | `[]` | Tolerations to use for the deployment. | | userNamespace | string | `"jupyter-pods"` | Namespace to use for user resources. | ----------------------------------------------- -Autogenerated from chart metadata using [helm-docs v1.11.0](https://github.com/norwoodj/helm-docs/releases/v1.11.0) diff --git a/helm/ambassador/values.yaml b/helm/ambassador/values.yaml index f3f6be41..0a78ca53 100644 --- a/helm/ambassador/values.yaml +++ b/helm/ambassador/values.yaml @@ -1,8 +1,7 @@ # Default values for ambassador. # This is a YAML-formatted file. # Declare variables to be passed into your templates. - -# -- (map) Global configuration options. +# Global configuration global: # -- (string) Environment name. This should be the same as vpcname if you're doing an AWS deployment. Currently this is being used to share ALB's if you have multiple namespaces. Might be used other places too. environment: default diff --git a/helm/arborist/Chart.yaml b/helm/arborist/Chart.yaml index 3ef314d6..39696872 100644 --- a/helm/arborist/Chart.yaml +++ b/helm/arborist/Chart.yaml @@ -15,7 +15,7 @@ type: application # This is the chart version. This version number should be incremented each time you make changes # to the chart and its templates, including the app version. # Versions are expected to follow Semantic Versioning (https://semver.org/) -version: 0.1.9 +version: 0.1.11 # This is the version number of the application being deployed. This version number should be # incremented each time you make changes to the application. Versions are not expected to @@ -25,7 +25,7 @@ appVersion: "master" dependencies: - name: common - version: 0.1.8 + version: 0.1.10 repository: file://../common - name: postgresql version: 11.9.13 diff --git a/helm/arborist/README.md b/helm/arborist/README.md index 13f542c6..74cb57d6 100644 --- a/helm/arborist/README.md +++ b/helm/arborist/README.md @@ -1,6 +1,6 @@ # arborist -![Version: 0.1.9](https://img.shields.io/badge/Version-0.1.9-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: master](https://img.shields.io/badge/AppVersion-master-informational?style=flat-square) +![Version: 0.1.11](https://img.shields.io/badge/Version-0.1.11-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: master](https://img.shields.io/badge/AppVersion-master-informational?style=flat-square) A Helm chart for gen3 arborist @@ -8,7 +8,7 @@ A Helm chart for gen3 arborist | Repository | Name | Version | |------------|------|---------| -| file://../common | common | 0.1.8 | +| file://../common | common | 0.1.10 | | https://charts.bitnami.com/bitnami | postgresql | 11.9.13 | ## Values @@ -28,13 +28,21 @@ A Helm chart for gen3 arborist | datadogTraceSampleRate | int | `1` | A value between 0 and 1, that represents the percentage of requests that will be traced. For example, a value of 0.5 means that 50% of requests will be traced. | | env | list | `[{"name":"JWKS_ENDPOINT","value":"http://fence-service/.well-known/jwks"}]` | Environment variables to pass to the container | | env[0] | string | `{"name":"JWKS_ENDPOINT","value":"http://fence-service/.well-known/jwks"}` | The URL of the JSON Web Key Set (JWKS) endpoint for authentication | +| externalSecrets | map | `{"dbcreds":null}` | External Secrets settings. | +| externalSecrets.dbcreds | string | `nil` | Will override the name of the aws secrets manager secret. Default is "Values.global.environment-.Chart.Name-creds" | | fullnameOverride | string | `""` | Override the full name of the deployment. | -| global | map | `{"ddEnabled":false,"dev":true,"dictionaryUrl":"https://s3.amazonaws.com/dictionary-artifacts/datadictionary/develop/schema.json","dispatcherJobNum":10,"environment":"default","hostname":"localhost","kubeBucket":"kube-gen3","logsBucket":"logs-gen3","minAvialable":1,"netPolicy":true,"pdb":false,"portalApp":"gitops","postgres":{"dbCreate":true,"master":{"host":null,"password":null,"port":"5432","username":"postgres"}},"publicDataSets":true,"revproxyArn":"arn:aws:acm:us-east-1:123456:certificate","tierAccessLevel":"libre"}` | Global configuration options. | +| global.aws | map | `{"awsAccessKeyId":null,"awsSecretAccessKey":null,"enabled":false}` | AWS configuration | +| global.aws.awsAccessKeyId | string | `nil` | Credentials for AWS stuff. | +| global.aws.awsSecretAccessKey | string | `nil` | Credentials for AWS stuff. | +| global.aws.enabled | bool | `false` | Set to true if deploying to AWS. Controls ingress annotations. | | global.ddEnabled | bool | `false` | Whether Datadog is enabled. | | global.dev | bool | `true` | Whether the deployment is for development purposes. | | global.dictionaryUrl | string | `"https://s3.amazonaws.com/dictionary-artifacts/datadictionary/develop/schema.json"` | URL of the data dictionary. | -| global.dispatcherJobNum | int | `10` | Number of dispatcher jobs. | +| global.dispatcherJobNum | int | `"10"` | Number of dispatcher jobs. | | global.environment | string | `"default"` | Environment name. This should be the same as vpcname if you're doing an AWS deployment. Currently this is being used to share ALB's if you have multiple namespaces. Might be used other places too. | +| global.externalSecrets | map | `{"deploy":false,"separateSecretStore":false}` | External Secrets settings. | +| global.externalSecrets.deploy | bool | `false` | Will use ExternalSecret resources to pull secrets from Secrets Manager instead of creating them locally. Be cautious as this will override any arborist secrets you have deployed. | +| global.externalSecrets.separateSecretStore | string | `false` | Will deploy a separate External Secret Store for this service. | | global.hostname | string | `"localhost"` | Hostname for the deployment. | | global.kubeBucket | string | `"kube-gen3"` | S3 bucket name for Kubernetes manifest files. | | global.logsBucket | string | `"logs-gen3"` | S3 bucket name for log files. | @@ -42,8 +50,8 @@ A Helm chart for gen3 arborist | global.netPolicy | bool | `true` | Whether network policies are enabled. | | global.pdb | bool | `false` | If the service will be deployed with a Pod Disruption Budget. Note- you need to have more than 2 replicas for the pdb to be deployed. | | global.portalApp | string | `"gitops"` | Portal application name. | -| global.postgres | map | `{"dbCreate":true,"master":{"host":null,"password":null,"port":"5432","username":"postgres"}}` | Postgres database configuration. | | global.postgres.dbCreate | bool | `true` | Whether the database should be created. | +| global.postgres.externalSecret | string | `""` | Name of external secret. Disabled if empty | | global.postgres.master | map | `{"host":null,"password":null,"port":"5432","username":"postgres"}` | Master credentials to postgres. This is going to be the default postgres server being used for each service, unless each service specifies their own postgres | | global.postgres.master.host | string | `nil` | hostname of postgres server | | global.postgres.master.password | string | `nil` | password for superuser in postgres. This is used to create or restore databases | @@ -81,6 +89,9 @@ A Helm chart for gen3 arborist | resources.requests | map | `{"cpu":0.1,"memory":"12Mi"}` | The amount of resources that the container requests | | resources.requests.cpu | string | `0.1` | The amount of CPU requested | | resources.requests.memory | string | `"12Mi"` | The amount of memory requested | +| secrets | map | `{"awsAccessKeyId":null,"awsSecretAccessKey":null}` | Secret information for External Secrets. | +| secrets.awsAccessKeyId | str | `nil` | AWS access key ID. Overrides global key. | +| secrets.awsSecretAccessKey | str | `nil` | AWS secret access key ID. Overrides global key. | | securityContext | map | `{}` | Security context to apply to the container | | selectorLabels | map | `nil` | Will completely override the selectorLabels defined in the common chart's _label_setup.tpl | | service | map | `{"port":80,"type":"ClusterIP"}` | Kubernetes service information. | @@ -94,5 +105,3 @@ A Helm chart for gen3 arborist | volumeMounts | list | `[]` | Volume mounts to attach to the container | | volumes | list | `[]` | Volumes to attach to the pod | ----------------------------------------------- -Autogenerated from chart metadata using [helm-docs v1.11.0](https://github.com/norwoodj/helm-docs/releases/v1.11.0) diff --git a/helm/arborist/templates/_helpers.tpl b/helm/arborist/templates/_helpers.tpl index 2aed27dc..9a85f4bd 100644 --- a/helm/arborist/templates/_helpers.tpl +++ b/helm/arborist/templates/_helpers.tpl @@ -77,4 +77,5 @@ Create the name of the service account to use {{- else }} {{- default .Values.postgres.password }} {{- end }} -{{- end }} \ No newline at end of file +{{- end }} + diff --git a/helm/arborist/templates/aws-config.yaml b/helm/arborist/templates/aws-config.yaml new file mode 100644 index 00000000..398770d3 --- /dev/null +++ b/helm/arborist/templates/aws-config.yaml @@ -0,0 +1,3 @@ +{{- if or (.Values.secrets.awsSecretAccessKey) (.Values.global.aws.awsSecretAccessKey ) }} +{{ include "common.awsconfig" . }} +{{- end -}} \ No newline at end of file diff --git a/helm/arborist/templates/db-init.yaml b/helm/arborist/templates/db-init.yaml index abbefb6e..5ef14e87 100644 --- a/helm/arborist/templates/db-init.yaml +++ b/helm/arborist/templates/db-init.yaml @@ -1,6 +1,6 @@ -{{ include "common.db_setup_job" . }} ---- {{ include "common.db-secret" . }} --- -{{ include "common.db_setup_sa" . }} +{{ include "common.db_setup_job" . }} --- +{{ include "common.db_setup_sa" . }} +--- \ No newline at end of file diff --git a/helm/arborist/templates/external-secret.yaml b/helm/arborist/templates/external-secret.yaml new file mode 100644 index 00000000..70c278fe --- /dev/null +++ b/helm/arborist/templates/external-secret.yaml @@ -0,0 +1 @@ +{{ include "common.externalSecret.db" . }} \ No newline at end of file diff --git a/helm/arborist/templates/secret-store.yaml b/helm/arborist/templates/secret-store.yaml new file mode 100644 index 00000000..771c7760 --- /dev/null +++ b/helm/arborist/templates/secret-store.yaml @@ -0,0 +1,3 @@ +{{ if .Values.global.externalSecrets.separateSecretStore }} +{{ include "common.secretstore" . }} +{{- end }} \ No newline at end of file diff --git a/helm/arborist/values.yaml b/helm/arborist/values.yaml index a2cbfcbf..c472742f 100644 --- a/helm/arborist/values.yaml +++ b/helm/arborist/values.yaml @@ -2,14 +2,25 @@ # This is a YAML-formatted file. # Declare variables to be passed into your templates. -# -- (map) Global configuration options. + +# Global configuration global: + # -- (map) AWS configuration + aws: + # -- (bool) Set to true if deploying to AWS. Controls ingress annotations. + enabled: false + # -- (string) Credentials for AWS stuff. + awsAccessKeyId: + # -- (string) Credentials for AWS stuff. + awsSecretAccessKey: # -- (bool) Whether the deployment is for development purposes. dev: true - # -- (map) Postgres database configuration. + postgres: # -- (bool) Whether the database should be created. dbCreate: true + # -- (string) Name of external secret. Disabled if empty + externalSecret: "" # -- (map) Master credentials to postgres. This is going to be the default postgres server being used for each service, unless each service specifies their own postgres master: # -- (string) hostname of postgres server @@ -41,13 +52,30 @@ global: # -- (bool) Whether network policies are enabled. netPolicy: true # -- (int) Number of dispatcher jobs. - dispatcherJobNum: 10 + dispatcherJobNum: "10" # -- (bool) Whether Datadog is enabled. ddEnabled: false # -- (bool) If the service will be deployed with a Pod Disruption Budget. Note- you need to have more than 2 replicas for the pdb to be deployed. pdb: false # -- (int) The minimum amount of pods that are available at all times if the PDB is deployed. minAvialable: 1 + # -- (map) External Secrets settings. + externalSecrets: + # -- (bool) Will use ExternalSecret resources to pull secrets from Secrets Manager instead of creating them locally. Be cautious as this will override any arborist secrets you have deployed. + deploy: false + # -- (string) Will deploy a separate External Secret Store for this service. + separateSecretStore: false + +# -- (map) External Secrets settings. +externalSecrets: + # -- (string) Will override the name of the aws secrets manager secret. Default is "Values.global.environment-.Chart.Name-creds" + dbcreds: +# -- (map) Secret information for External Secrets. +secrets: + # -- (str) AWS access key ID. Overrides global key. + awsAccessKeyId: + # -- (str) AWS secret access key ID. Overrides global key. + awsSecretAccessKey: # -- (map) Postgres database configuration. If db does not exist in postgres cluster and dbCreate is set ot true then these databases will be created for you postgres: diff --git a/helm/argo-wrapper/Chart.yaml b/helm/argo-wrapper/Chart.yaml index 5d320e9d..57d20124 100644 --- a/helm/argo-wrapper/Chart.yaml +++ b/helm/argo-wrapper/Chart.yaml @@ -15,7 +15,7 @@ type: application # This is the chart version. This version number should be incremented each time you make changes # to the chart and its templates, including the app version. # Versions are expected to follow Semantic Versioning (https://semver.org/) -version: 0.1.5 +version: 0.1.7 # This is the version number of the application being deployed. This version number should be # incremented each time you make changes to the application. Versions are not expected to @@ -25,5 +25,5 @@ appVersion: "master" dependencies: - name: common - version: 0.1.8 + version: 0.1.10 repository: file://../common diff --git a/helm/argo-wrapper/README.md b/helm/argo-wrapper/README.md index b5f7b3a1..d6ce7750 100644 --- a/helm/argo-wrapper/README.md +++ b/helm/argo-wrapper/README.md @@ -1,6 +1,6 @@ # argo-wrapper -![Version: 0.1.5](https://img.shields.io/badge/Version-0.1.5-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: master](https://img.shields.io/badge/AppVersion-master-informational?style=flat-square) +![Version: 0.1.7](https://img.shields.io/badge/Version-0.1.7-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: master](https://img.shields.io/badge/AppVersion-master-informational?style=flat-square) A Helm chart for gen3 Argo Wrapper Service @@ -8,7 +8,7 @@ A Helm chart for gen3 Argo Wrapper Service | Repository | Name | Version | |------------|------|---------| -| file://../common | common | 0.1.8 | +| file://../common | common | 0.1.10 | ## Values @@ -32,7 +32,6 @@ A Helm chart for gen3 Argo Wrapper Service | datadogProfilingEnabled | bool | `true` | If enabled, the Datadog Agent will collect profiling data for your application using the Continuous Profiler. This data can be used to identify performance bottlenecks and optimize your application. | | datadogTraceSampleRate | int | `1` | A value between 0 and 1, that represents the percentage of requests that will be traced. For example, a value of 0.5 means that 50% of requests will be traced. | | environment | string | `"default"` | Environment name. | -| global | map | `{"ddEnabled":false,"environment":"default","minAvialable":1,"pdb":false}` | Global configuration options. | | global.ddEnabled | bool | `false` | Whether Datadog is enabled. | | global.environment | string | `"default"` | Environment name. This should be the same as vpcname if you're doing an AWS deployment. Currently this is being used to share ALB's if you have multiple namespaces. Might be used other places too. | | global.minAvialable | int | `1` | The minimum amount of pods that are available at all times if the PDB is deployed. | @@ -65,5 +64,3 @@ A Helm chart for gen3 Argo Wrapper Service | volumeMounts | list | `[{"mountPath":"/argo.json","name":"argo-config","readOnly":true,"subPath":"argo.json"}]` | Volumes to mount to the pod. | | volumes | list | `[{"configMap":{"items":[{"key":"argo.json","path":"argo.json"}],"name":"manifest-argo"},"name":"argo-config"}]` | Volumes to attach to the pod. | ----------------------------------------------- -Autogenerated from chart metadata using [helm-docs v1.11.0](https://github.com/norwoodj/helm-docs/releases/v1.11.0) diff --git a/helm/argo-wrapper/values.yaml b/helm/argo-wrapper/values.yaml index 47c711b0..e98ca8a7 100644 --- a/helm/argo-wrapper/values.yaml +++ b/helm/argo-wrapper/values.yaml @@ -2,7 +2,8 @@ # This is a YAML-formatted file. # Declare variables to be passed into your templates. -# -- (map) Global configuration options. + +# Global configuration global: # -- (string) Environment name. This should be the same as vpcname if you're doing an AWS deployment. Currently this is being used to share ALB's if you have multiple namespaces. Might be used other places too. environment: default diff --git a/helm/audit/Chart.yaml b/helm/audit/Chart.yaml index fbd974a8..2295c602 100644 --- a/helm/audit/Chart.yaml +++ b/helm/audit/Chart.yaml @@ -15,7 +15,7 @@ type: application # This is the chart version. This version number should be incremented each time you make changes # to the chart and its templates, including the app version. # Versions are expected to follow Semantic Versioning (https://semver.org/) -version: 0.1.10 +version: 0.1.12 # This is the version number of the application being deployed. This version number should be # incremented each time you make changes to the application. Versions are not expected to @@ -24,7 +24,7 @@ appVersion: "master" dependencies: - name: common - version: 0.1.8 + version: 0.1.10 repository: file://../common - name: postgresql version: 11.9.13 diff --git a/helm/audit/README.md b/helm/audit/README.md index 59d85f1e..43885245 100644 --- a/helm/audit/README.md +++ b/helm/audit/README.md @@ -1,6 +1,6 @@ # audit -![Version: 0.1.10](https://img.shields.io/badge/Version-0.1.10-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: master](https://img.shields.io/badge/AppVersion-master-informational?style=flat-square) +![Version: 0.1.12](https://img.shields.io/badge/Version-0.1.12-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: master](https://img.shields.io/badge/AppVersion-master-informational?style=flat-square) A Helm chart for Kubernetes @@ -8,7 +8,7 @@ A Helm chart for Kubernetes | Repository | Name | Version | |------------|------|---------| -| file://../common | common | 0.1.8 | +| file://../common | common | 0.1.10 | | https://charts.bitnami.com/bitnami | postgresql | 11.9.13 | ## Values @@ -36,13 +36,23 @@ A Helm chart for Kubernetes | datadogProfilingEnabled | bool | `true` | If enabled, the Datadog Agent will collect profiling data for your application using the Continuous Profiler. This data can be used to identify performance bottlenecks and optimize your application. | | datadogTraceSampleRate | int | `1` | A value between 0 and 1, that represents the percentage of requests that will be traced. For example, a value of 0.5 means that 50% of requests will be traced. | | env | list | `[{"name":"DEBUG","value":"false"},{"name":"ARBORIST_URL","valueFrom":{"configMapKeyRef":{"key":"arborist_url","name":"manifest-global","optional":true}}}]` | Environment variables to pass to the container | +| externalSecrets | map | `{"auditG3auto":null,"createK8sAuditSecret":false,"dbcreds":null}` | External Secrets settings. | +| externalSecrets.auditG3auto | string | `nil` | Will override the name of the aws secrets manager secret. Default is "audit-g3auto" | +| externalSecrets.createK8sAuditSecret | string | `false` | Will create the Helm "audit-g3auto" secret even if Secrets Manager is enabled. This is helpful if you are wanting to use External Secrets for some, but not all secrets. | +| externalSecrets.dbcreds | string | `nil` | Will override the name of the aws secrets manager secret. Default is "Values.global.environment-.Chart.Name-creds" | | fullnameOverride | string | `""` | Override the full name of the chart, which is used as the name of resources created by the chart | -| global | map | `{"ddEnabled":false,"dev":true,"dictionaryUrl":"https://s3.amazonaws.com/dictionary-artifacts/datadictionary/develop/schema.json","dispatcherJobNum":10,"environment":"default","hostname":"localhost","kubeBucket":"kube-gen3","logsBucket":"logs-gen3","minAvialable":1,"netPolicy":true,"pdb":false,"portalApp":"gitops","postgres":{"dbCreate":true,"master":{"host":null,"password":null,"port":"5432","username":"postgres"}},"publicDataSets":true,"revproxyArn":"arn:aws:acm:us-east-1:123456:certificate","tierAccessLevel":"libre"}` | Global configuration options. | +| global.aws | map | `{"awsAccessKeyId":null,"awsSecretAccessKey":null,"enabled":false}` | AWS configuration | +| global.aws.awsAccessKeyId | string | `nil` | Credentials for AWS stuff. | +| global.aws.awsSecretAccessKey | string | `nil` | Credentials for AWS stuff. | +| global.aws.enabled | bool | `false` | Set to true if deploying to AWS. Controls ingress annotations. | | global.ddEnabled | bool | `false` | Whether Datadog is enabled. | | global.dev | bool | `true` | Whether the deployment is for development purposes. | | global.dictionaryUrl | string | `"https://s3.amazonaws.com/dictionary-artifacts/datadictionary/develop/schema.json"` | URL of the data dictionary. | -| global.dispatcherJobNum | int | `10` | Number of dispatcher jobs. | +| global.dispatcherJobNum | int | `"10"` | Number of dispatcher jobs. | | global.environment | string | `"default"` | Environment name. This should be the same as vpcname if you're doing an AWS deployment. Currently this is being used to share ALB's if you have multiple namespaces. Might be used other places too. | +| global.externalSecrets | map | `{"deploy":false,"separateSecretStore":false}` | External Secrets settings. | +| global.externalSecrets.deploy | bool | `false` | Will use ExternalSecret resources to pull secrets from Secrets Manager instead of creating them locally. Be cautious as this will override any audit secrets you have deployed. | +| global.externalSecrets.separateSecretStore | string | `false` | Will deploy a separate External Secret Store for this service. | | global.hostname | string | `"localhost"` | Hostname for the deployment. | | global.kubeBucket | string | `"kube-gen3"` | S3 bucket name for Kubernetes manifest files. | | global.logsBucket | string | `"logs-gen3"` | S3 bucket name for log files. | @@ -50,8 +60,8 @@ A Helm chart for Kubernetes | global.netPolicy | bool | `true` | Whether network policies are enabled. | | global.pdb | bool | `false` | If the service will be deployed with a Pod Disruption Budget. Note- you need to have more than 2 replicas for the pdb to be deployed. | | global.portalApp | string | `"gitops"` | Portal application name. | -| global.postgres | map | `{"dbCreate":true,"master":{"host":null,"password":null,"port":"5432","username":"postgres"}}` | Postgres database configuration. | | global.postgres.dbCreate | bool | `true` | Whether the database should be created. | +| global.postgres.externalSecret | string | `""` | Name of external secret. Disabled if empty | | global.postgres.master | map | `{"host":null,"password":null,"port":"5432","username":"postgres"}` | Master credentials to postgres. This is going to be the default postgres server being used for each service, unless each service specifies their own postgres | | global.postgres.master.host | string | `nil` | hostname of postgres server | | global.postgres.master.password | string | `nil` | password for superuser in postgres. This is used to create or restore databases | @@ -91,6 +101,9 @@ A Helm chart for Kubernetes | resources.requests | map | `{"cpu":0.2,"memory":"120Mi"}` | The amount of resources that the container requests | | resources.requests.cpu | string | `0.2` | The amount of CPU requested | | resources.requests.memory | string | `"120Mi"` | The amount of memory requested | +| secrets | map | `{"awsAccessKeyId":null,"awsSecretAccessKey":null}` | Secret information for External Secrets. | +| secrets.awsAccessKeyId | str | `nil` | AWS access key ID. Overrides global key. | +| secrets.awsSecretAccessKey | str | `nil` | AWS secret access key ID. Overrides global key. | | securityContext | map | `{}` | Security context for the containers in the pod | | selectorLabels | map | `nil` | Will completely override the selectorLabels defined in the common chart's _label_setup.tpl | | server.AWS_CREDENTIALS | map | `{}` | AWS credentials to access SQS queue. | @@ -114,5 +127,3 @@ A Helm chart for Kubernetes | volumeMounts | list | `[]` | Volumes to mount to the container. | | volumes | list | `[]` | Volumes to attach to the container. | ----------------------------------------------- -Autogenerated from chart metadata using [helm-docs v1.11.0](https://github.com/norwoodj/helm-docs/releases/v1.11.0) diff --git a/helm/audit/templates/_helpers.tpl b/helm/audit/templates/_helpers.tpl index e255d758..6f70cc66 100644 --- a/helm/audit/templates/_helpers.tpl +++ b/helm/audit/templates/_helpers.tpl @@ -67,16 +67,6 @@ Create the name of the service account to use {{- end }} {{- end }} - - -{{/* -Create the name of the service account to use -*/}} -{{- define "audit.secretName" -}} -{{- default "audit-g3auto" }} -{{- end }} - - {{/* Postgres Password lookup */}} @@ -87,4 +77,13 @@ Create the name of the service account to use {{- else }} {{- default .Values.postgres.password }} {{- end }} -{{- end }} \ No newline at end of file +{{- end }} + + +{{/* + Audit g3 Auto Secrets Manager Name +*/}} +{{- define "audit-g3auto" -}} +{{- default "audit-g3auto" .Values.externalSecrets.auditG3auto }} +{{- end }} + diff --git a/helm/audit/templates/aws-config.yaml b/helm/audit/templates/aws-config.yaml new file mode 100644 index 00000000..398770d3 --- /dev/null +++ b/helm/audit/templates/aws-config.yaml @@ -0,0 +1,3 @@ +{{- if or (.Values.secrets.awsSecretAccessKey) (.Values.global.aws.awsSecretAccessKey ) }} +{{ include "common.awsconfig" . }} +{{- end -}} \ No newline at end of file diff --git a/helm/audit/templates/db-init.yaml b/helm/audit/templates/db-init.yaml index 50bd8e8f..5ef14e87 100644 --- a/helm/audit/templates/db-init.yaml +++ b/helm/audit/templates/db-init.yaml @@ -1,6 +1,6 @@ -{{ include "common.db_setup_job" . }} ---- {{ include "common.db-secret" . }} --- +{{ include "common.db_setup_job" . }} +--- {{ include "common.db_setup_sa" . }} --- \ No newline at end of file diff --git a/helm/audit/templates/external-secret.yaml b/helm/audit/templates/external-secret.yaml new file mode 100644 index 00000000..d925feaa --- /dev/null +++ b/helm/audit/templates/external-secret.yaml @@ -0,0 +1,21 @@ +{{ if .Values.global.externalSecrets.deploy }} +apiVersion: external-secrets.io/v1beta1 +kind: ExternalSecret +metadata: + name: audit-g3auto +spec: + refreshInterval: 5m + secretStoreRef: + name: {{include "common.SecretStore" .}} + kind: SecretStore + target: + name: audit-g3auto + creationPolicy: Owner + data: + - secretKey: audit-service-config.yaml + remoteRef: + #name of secret in secrets manager + key: {{include "audit-g3auto" .}} +{{- end }} +--- +{{ include "common.externalSecret.db" . }} \ No newline at end of file diff --git a/helm/audit/templates/secret-store.yaml b/helm/audit/templates/secret-store.yaml new file mode 100644 index 00000000..771c7760 --- /dev/null +++ b/helm/audit/templates/secret-store.yaml @@ -0,0 +1,3 @@ +{{ if .Values.global.externalSecrets.separateSecretStore }} +{{ include "common.secretstore" . }} +{{- end }} \ No newline at end of file diff --git a/helm/audit/templates/secrets.yaml b/helm/audit/templates/secrets.yaml index 945c8d36..b1073381 100644 --- a/helm/audit/templates/secrets.yaml +++ b/helm/audit/templates/secrets.yaml @@ -1,7 +1,8 @@ +{{- if or (not .Values.global.externalSecrets.deploy) (and .Values.global.externalSecrets.deploy .Values.externalSecrets.createK8sAuditSecret) }} apiVersion: v1 kind: Secret metadata: - name: {{ include "audit.secretName" . }} + name: audit-g3auto labels: {{- include "audit.labels" . | nindent 4 }} stringData: @@ -49,4 +50,5 @@ stringData: # whether to return usernames in query responses, # and to allow querying by username - QUERY_USERNAMES: true \ No newline at end of file + QUERY_USERNAMES: true +{{- end }} \ No newline at end of file diff --git a/helm/audit/values.yaml b/helm/audit/values.yaml index 2343bb89..bba64501 100644 --- a/helm/audit/values.yaml +++ b/helm/audit/values.yaml @@ -1,14 +1,25 @@ # Default values for audit. # This is a YAML-formatted file. # Declare variables to be passed into your templates. -# -- (map) Global configuration options. + +# Global configuration global: + # -- (map) AWS configuration + aws: + # -- (bool) Set to true if deploying to AWS. Controls ingress annotations. + enabled: false + # -- (string) Credentials for AWS stuff. + awsAccessKeyId: + # -- (string) Credentials for AWS stuff. + awsSecretAccessKey: # -- (bool) Whether the deployment is for development purposes. dev: true - # -- (map) Postgres database configuration. + postgres: # -- (bool) Whether the database should be created. dbCreate: true + # -- (string) Name of external secret. Disabled if empty + externalSecret: "" # -- (map) Master credentials to postgres. This is going to be the default postgres server being used for each service, unless each service specifies their own postgres master: # -- (string) hostname of postgres server @@ -40,13 +51,34 @@ global: # -- (bool) Whether network policies are enabled. netPolicy: true # -- (int) Number of dispatcher jobs. - dispatcherJobNum: 10 + dispatcherJobNum: "10" # -- (bool) Whether Datadog is enabled. ddEnabled: false # -- (bool) If the service will be deployed with a Pod Disruption Budget. Note- you need to have more than 2 replicas for the pdb to be deployed. pdb: false # -- (int) The minimum amount of pods that are available at all times if the PDB is deployed. minAvialable: 1 + # -- (map) External Secrets settings. + externalSecrets: + # -- (bool) Will use ExternalSecret resources to pull secrets from Secrets Manager instead of creating them locally. Be cautious as this will override any audit secrets you have deployed. + deploy: false + # -- (string) Will deploy a separate External Secret Store for this service. + separateSecretStore: false + +# -- (map) External Secrets settings. +externalSecrets: + # -- (string) Will create the Helm "audit-g3auto" secret even if Secrets Manager is enabled. This is helpful if you are wanting to use External Secrets for some, but not all secrets. + createK8sAuditSecret: false + # -- (string) Will override the name of the aws secrets manager secret. Default is "audit-g3auto" + auditG3auto: + # -- (string) Will override the name of the aws secrets manager secret. Default is "Values.global.environment-.Chart.Name-creds" + dbcreds: +# -- (map) Secret information for External Secrets. +secrets: + # -- (str) AWS access key ID. Overrides global key. + awsAccessKeyId: + # -- (str) AWS secret access key ID. Overrides global key. + awsSecretAccessKey: # -- (map) Postgres database configuration. If db does not exist in postgres cluster and dbCreate is set ot true then these databases will be created for you postgres: diff --git a/helm/aws-es-proxy/Chart.yaml b/helm/aws-es-proxy/Chart.yaml index 80466f8b..7fea05b3 100644 --- a/helm/aws-es-proxy/Chart.yaml +++ b/helm/aws-es-proxy/Chart.yaml @@ -15,7 +15,7 @@ type: application # This is the chart version. This version number should be incremented each time you make changes # to the chart and its templates, including the app version. # Versions are expected to follow Semantic Versioning (https://semver.org/) -version: 0.1.7 +version: 0.1.9 # This is the version number of the application being deployed. This version number should be # incremented each time you make changes to the application. Versions are not expected to @@ -25,5 +25,5 @@ appVersion: "master" dependencies: - name: common - version: 0.1.8 + version: 0.1.10 repository: file://../common diff --git a/helm/aws-es-proxy/README.md b/helm/aws-es-proxy/README.md index 43ce7cb2..873a0e41 100644 --- a/helm/aws-es-proxy/README.md +++ b/helm/aws-es-proxy/README.md @@ -1,6 +1,6 @@ # aws-es-proxy -![Version: 0.1.7](https://img.shields.io/badge/Version-0.1.7-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: master](https://img.shields.io/badge/AppVersion-master-informational?style=flat-square) +![Version: 0.1.9](https://img.shields.io/badge/Version-0.1.9-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: master](https://img.shields.io/badge/AppVersion-master-informational?style=flat-square) A Helm chart for AWS ES Proxy Service for gen3 @@ -8,7 +8,7 @@ A Helm chart for AWS ES Proxy Service for gen3 | Repository | Name | Version | |------------|------|---------| -| file://../common | common | 0.1.8 | +| file://../common | common | 0.1.10 | ## Values @@ -26,9 +26,16 @@ A Helm chart for AWS ES Proxy Service for gen3 | datadogProfilingEnabled | bool | `true` | If enabled, the Datadog Agent will collect profiling data for your application using the Continuous Profiler. This data can be used to identify performance bottlenecks and optimize your application. | | datadogTraceSampleRate | int | `1` | A value between 0 and 1, that represents the percentage of requests that will be traced. For example, a value of 0.5 means that 50% of requests will be traced. | | esEndpoint | str | `"test.us-east-1.es.amazonaws.com"` | Elasticsearch endpoint in AWS | -| global | map | `{"ddEnabled":false,"environment":"default","minAvialable":1,"pdb":false}` | Global configuration options. | +| externalSecrets | map | `{"awsCreds":"aws-es-proxy-aws-credentials"}` | External Secrets settings. | +| externalSecrets.awsCreds | string | `"aws-es-proxy-aws-credentials"` | Will override the name of the aws secrets manager secret. Default is "Values.global.environment-.Chart.Name-creds" | +| global.aws | map | `{"awsAccessKeyId":null,"awsSecretAccessKey":null,"enabled":false}` | AWS configuration | +| global.aws.awsAccessKeyId | string | `nil` | Credentials for AWS stuff. | +| global.aws.awsSecretAccessKey | string | `nil` | Credentials for AWS stuff. | +| global.aws.enabled | bool | `false` | Set to true if deploying to AWS. Controls ingress annotations. | | global.ddEnabled | bool | `false` | Whether Datadog is enabled. | | global.environment | string | `"default"` | Environment name. This should be the same as vpcname if you're doing an AWS deployment. Currently this is being used to share ALB's if you have multiple namespaces. Might be used other places too. | +| global.externalSecrets.deploy | bool | `false` | Will use ExternalSecret resources to pull secrets from Secrets Manager instead of creating them locally. Be cautious as this will override any audit secrets you have deployed. | +| global.externalSecrets.separateSecretStore | string | `false` | Will deploy a separate External Secret Store for this service. | | global.minAvialable | int | `1` | The minimum amount of pods that are available at all times if the PDB is deployed. | | global.pdb | bool | `false` | If the service will be deployed with a Pod Disruption Budget. Note- you need to have more than 2 replicas for the pdb to be deployed. | | image | map | `{"pullPolicy":"Always","repository":"quay.io/cdis/aws-es-proxy","tag":""}` | Docker image information. | @@ -47,9 +54,9 @@ A Helm chart for AWS ES Proxy Service for gen3 | resources.requests.cpu | string | `0.1` | The amount of CPU requested | | resources.requests.memory | string | `"250Mi"` | The amount of memory requested | | revisionHistoryLimit | int | `2` | Number of old revisions to retain | -| secrets | map | `{"awsAccessKeyId":"","awsSecretAccessKey":""}` | Secret information | -| secrets.awsAccessKeyId | str | `""` | AWS access key ID | -| secrets.awsSecretAccessKey | str | `""` | AWS secret access key | +| secrets | map | `{"awsAccessKeyId":null,"awsSecretAccessKey":null}` | Secret information to access AWS ES cluster. | +| secrets.awsAccessKeyId | str | `nil` | AWS access key ID. Overrides global key. | +| secrets.awsSecretAccessKey | str | `nil` | AWS secret access key ID. Overrides global key. | | selectorLabels | map | `nil` | Will completely override the selectorLabels defined in the common chart's _label_setup.tpl | | service | map | `{"port":9200,"type":"ClusterIP"}` | Kubernetes service information. | | service.port | int | `9200` | The port number that the service exposes. | @@ -58,7 +65,5 @@ A Helm chart for AWS ES Proxy Service for gen3 | strategy.rollingUpdate.maxSurge | int | `1` | Number of additional replicas to add during rollout. | | strategy.rollingUpdate.maxUnavailable | int | `0` | Maximum amount of pods that can be unavailable during the update. | | volumeMounts | list | `[{"mountPath":"/root/.aws","name":"credentials","readOnly":true}]` | Volumes to mount to the pod. | -| volumes | list | `[{"name":"credentials","secret":{"secretName":"aws-es-proxy"}}]` | Volumes to attach to the pod | +| volumes | list | `nil` | Volumes to attach to the pod | ----------------------------------------------- -Autogenerated from chart metadata using [helm-docs v1.11.0](https://github.com/norwoodj/helm-docs/releases/v1.11.0) diff --git a/helm/aws-es-proxy/templates/aws-config.yaml b/helm/aws-es-proxy/templates/aws-config.yaml new file mode 100644 index 00000000..4723e6b3 --- /dev/null +++ b/helm/aws-es-proxy/templates/aws-config.yaml @@ -0,0 +1,3 @@ +{{- if or (.Values.secrets.awsSecretAccessKey) (.Values.global.aws.awsSecretAccessKey ) }} +{{ include "common.awsconfig" . }} +{{- end }} \ No newline at end of file diff --git a/helm/aws-es-proxy/templates/aws-es-proxy.yaml b/helm/aws-es-proxy/templates/aws-es-proxy.yaml deleted file mode 100644 index 734cb48c..00000000 --- a/helm/aws-es-proxy/templates/aws-es-proxy.yaml +++ /dev/null @@ -1,10 +0,0 @@ -apiVersion: v1 -kind: Secret -metadata: - name: aws-es-proxy -type: Opaque -stringData: - credentials: | - [default] - aws_access_key_id={{.Values.secrets.awsAccessKeyId}} - aws_secret_access_key={{ .Values.secrets.awsSecretAccessKey}} \ No newline at end of file diff --git a/helm/aws-es-proxy/templates/deployment.yaml b/helm/aws-es-proxy/templates/deployment.yaml index 3c74d70e..cd555b93 100644 --- a/helm/aws-es-proxy/templates/deployment.yaml +++ b/helm/aws-es-proxy/templates/deployment.yaml @@ -33,10 +33,10 @@ spec: {{- end }} spec: automountServiceAccountToken: {{ .Values.automountServiceAccountToken }} - {{- with .Values.volumes }} volumes: - {{- toYaml . | nindent 8 }} - {{- end }} + - name: credentials + secret: + secretName: {{.Chart.Name}}-aws-config containers: - name: "esproxy" image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" diff --git a/helm/aws-es-proxy/templates/external-secrets.yaml b/helm/aws-es-proxy/templates/external-secrets.yaml new file mode 100644 index 00000000..16517911 --- /dev/null +++ b/helm/aws-es-proxy/templates/external-secrets.yaml @@ -0,0 +1,19 @@ +{{ if .Values.global.externalSecrets.deploy }} +apiVersion: external-secrets.io/v1beta1 +kind: ExternalSecret +metadata: + name: aws-es-proxy-aws-config +spec: + refreshInterval: 5m + secretStoreRef: + name: {{include "common.SecretStore" .}} + kind: SecretStore + target: + name: aws-es-proxy-aws-config + creationPolicy: Owner + data: + - secretKey: credentials + remoteRef: + #name of secret in secrets manager + key: {{ .Values.externalSecrets.awsCreds }} +{{- end }} \ No newline at end of file diff --git a/helm/aws-es-proxy/templates/secret-store.yaml b/helm/aws-es-proxy/templates/secret-store.yaml new file mode 100644 index 00000000..771c7760 --- /dev/null +++ b/helm/aws-es-proxy/templates/secret-store.yaml @@ -0,0 +1,3 @@ +{{ if .Values.global.externalSecrets.separateSecretStore }} +{{ include "common.secretstore" . }} +{{- end }} \ No newline at end of file diff --git a/helm/aws-es-proxy/values.yaml b/helm/aws-es-proxy/values.yaml index 5367ba70..11c1c200 100644 --- a/helm/aws-es-proxy/values.yaml +++ b/helm/aws-es-proxy/values.yaml @@ -2,8 +2,17 @@ # This is a YAML-formatted file. # Declare variables to be passed into your templates. -# -- (map) Global configuration options. + +# Global configuration global: + # -- (map) AWS configuration + aws: + # -- (bool) Set to true if deploying to AWS. Controls ingress annotations. + enabled: false + # -- (string) Credentials for AWS stuff. + awsAccessKeyId: + # -- (string) Credentials for AWS stuff. + awsSecretAccessKey: # -- (string) Environment name. This should be the same as vpcname if you're doing an AWS deployment. Currently this is being used to share ALB's if you have multiple namespaces. Might be used other places too. environment: default # -- (bool) Whether Datadog is enabled. @@ -12,6 +21,16 @@ global: pdb: false # -- (int) The minimum amount of pods that are available at all times if the PDB is deployed. minAvialable: 1 + externalSecrets: + # -- (bool) Will use ExternalSecret resources to pull secrets from Secrets Manager instead of creating them locally. Be cautious as this will override any audit secrets you have deployed. + deploy: false + # -- (string) Will deploy a separate External Secret Store for this service. + separateSecretStore: false + +# -- (map) External Secrets settings. +externalSecrets: + # -- (string) Will override the name of the aws secrets manager secret. Default is "Values.global.environment-.Chart.Name-creds" + awsCreds: "aws-es-proxy-aws-credentials" # -- (map) Annotations to add to the pod podAnnotations: @@ -27,6 +46,13 @@ autoscaling: # -- (int) The target CPU utilization percentage for autoscaling targetCPUUtilizationPercentage: 80 +# -- (map) Secret information to access AWS ES cluster. +secrets: + # -- (str) AWS access key ID. Overrides global key. + awsAccessKeyId: + # -- (str) AWS secret access key ID. Overrides global key. + awsSecretAccessKey: + # -- (int) Number of replicas for the deployment. replicaCount: 1 @@ -47,9 +73,6 @@ automountServiceAccountToken: false # -- (list) Volumes to attach to the pod volumes: - - name: credentials - secret: - secretName: aws-es-proxy # -- (map) Docker image information. image: @@ -93,13 +116,6 @@ service: # -- (int) The port number that the service exposes. port: 9200 -# -- (map) Secret information -secrets: - # -- (str) AWS access key ID - awsAccessKeyId: "" - # -- (str) AWS secret access key - awsSecretAccessKey: "" - # Values to determine the labels that are used for the deployment, pod, etc. # -- (string) Valid options are "production" or "dev". If invalid option is set- the value will default to "dev". release: "production" diff --git a/helm/common/Chart.yaml b/helm/common/Chart.yaml index 5007c4a7..11151e9d 100644 --- a/helm/common/Chart.yaml +++ b/helm/common/Chart.yaml @@ -15,7 +15,7 @@ type: library # This is the chart version. This version number should be incremented each time you make changes # to the chart and its templates, including the app version. # Versions are expected to follow Semantic Versioning (https://semver.org/) -version: 0.1.8 +version: 0.1.11 # This is the version number of the application being deployed. This version number should be # incremented each time you make changes to the application. Versions are not expected to diff --git a/helm/common/README.md b/helm/common/README.md index a93a01fa..1fe4bdf7 100644 --- a/helm/common/README.md +++ b/helm/common/README.md @@ -1,6 +1,6 @@ # common -![Version: 0.1.8](https://img.shields.io/badge/Version-0.1.8-informational?style=flat-square) ![Type: library](https://img.shields.io/badge/Type-library-informational?style=flat-square) ![AppVersion: master](https://img.shields.io/badge/AppVersion-master-informational?style=flat-square) +![Version: 0.1.11](https://img.shields.io/badge/Version-0.1.11-informational?style=flat-square) ![Type: library](https://img.shields.io/badge/Type-library-informational?style=flat-square) ![AppVersion: master](https://img.shields.io/badge/AppVersion-master-informational?style=flat-square) A Helm chart for provisioning databases in gen3 @@ -8,19 +8,20 @@ A Helm chart for provisioning databases in gen3 | Key | Type | Default | Description | |-----|------|---------|-------------| -| global | map | `{"ddEnabled":false,"dev":true,"dictionaryUrl":"https://s3.amazonaws.com/dictionary-artifacts/datadictionary/develop/schema.json","dispatcherJobNum":10,"environment":"default","hostname":"localhost","kubeBucket":"kube-gen3","logsBucket":"logs-gen3","netPolicy":true,"portalApp":"gitops","postgres":{"dbCreate":true,"master":{"host":null,"password":null,"port":"5432","username":"postgres"}},"publicDataSets":true,"revproxyArn":"arn:aws:acm:us-east-1:123456:certificate","tierAccessLevel":"libre"}` | Global configuration options. | +| global.aws | map | `{"region":"us-east-1"}` | AWS configuration | +| global.aws.region | string | `"us-east-1"` | AWS region for this deployment | | global.ddEnabled | bool | `false` | Whether Datadog is enabled. | | global.dev | bool | `true` | Whether the deployment is for development purposes. | | global.dictionaryUrl | string | `"https://s3.amazonaws.com/dictionary-artifacts/datadictionary/develop/schema.json"` | URL of the data dictionary. | -| global.dispatcherJobNum | int | `10` | Number of dispatcher jobs. | +| global.dispatcherJobNum | int | `"10"` | Number of dispatcher jobs. | | global.environment | string | `"default"` | Environment name. This should be the same as vpcname if you're doing an AWS deployment. Currently this is being used to share ALB's if you have multiple namespaces. Might be used other places too. | | global.hostname | string | `"localhost"` | Hostname for the deployment. | | global.kubeBucket | string | `"kube-gen3"` | S3 bucket name for Kubernetes manifest files. | | global.logsBucket | string | `"logs-gen3"` | S3 bucket name for log files. | | global.netPolicy | bool | `true` | Whether network policies are enabled. | | global.portalApp | string | `"gitops"` | Portal application name. | -| global.postgres | map | `{"dbCreate":true,"master":{"host":null,"password":null,"port":"5432","username":"postgres"}}` | Postgres database configuration. | | global.postgres.dbCreate | bool | `true` | Whether the database should be created. | +| global.postgres.externalSecret | string | `""` | Name of external secret. Disabled if empty | | global.postgres.master | map | `{"host":null,"password":null,"port":"5432","username":"postgres"}` | Master credentials to postgres. This is going to be the default postgres server being used for each service, unless each service specifies their own postgres | | global.postgres.master.host | string | `nil` | hostname of postgres server | | global.postgres.master.password | string | `nil` | password for superuser in postgres. This is used to create or restore databases | @@ -30,5 +31,3 @@ A Helm chart for provisioning databases in gen3 | global.revproxyArn | string | `"arn:aws:acm:us-east-1:123456:certificate"` | ARN of the reverse proxy certificate. | | global.tierAccessLevel | string | `"libre"` | Access level for tiers. acceptable values for `tier_access_level` are: `libre`, `regular` and `private`. If omitted, by default common will be treated as `private` | ----------------------------------------------- -Autogenerated from chart metadata using [helm-docs v1.11.0](https://github.com/norwoodj/helm-docs/releases/v1.11.0) diff --git a/helm/common/templates/_aws_config.tpl b/helm/common/templates/_aws_config.tpl new file mode 100644 index 00000000..be48047c --- /dev/null +++ b/helm/common/templates/_aws_config.tpl @@ -0,0 +1,18 @@ +{{/* + Credentials for all AWS stuff. +*/}} +{{ define "common.awsconfig" -}} +apiVersion: v1 +kind: Secret +metadata: + name: {{.Chart.Name}}-aws-config +type: Opaque +stringData: + credentials: | + [default] + aws_access_key_id={{ .Values.secrets.awsAccessKeyId | default .Values.global.aws.awsAccessKeyId}} + aws_secret_access_key={{ .Values.secrets.awsSecretAccessKey | default .Values.global.aws.awsSecretAccessKey}} +data: + access-key: {{ .Values.secrets.awsAccessKeyId | default .Values.global.aws.awsAccessKeyId | b64enc }} + secret-access-key: {{ .Values.secrets.awsSecretAccessKey | default .Values.global.aws.awsSecretAccessKey | b64enc }} +{{- end }} \ No newline at end of file diff --git a/helm/common/templates/_db_setup_job.tpl b/helm/common/templates/_db_setup_job.tpl index c3ddb395..49f12421 100644 --- a/helm/common/templates/_db_setup_job.tpl +++ b/helm/common/templates/_db_setup_job.tpl @@ -31,6 +31,7 @@ roleRef: # DB Setup Job {{- define "common.db_setup_job" -}} +{{- if or $.Values.global.postgres.dbCreate $.Values.postgres.dbCreate }} apiVersion: batch/v1 kind: Job metadata: @@ -59,16 +60,44 @@ spec: name: {{ .Release.Name }}-postgresql key: postgres-password optional: false + {{- else if $.Values.global.postgres.externalSecret }} + valueFrom: + secretKeyRef: + name: {{ $.Values.global.postgres.externalSecret }} + key: password + optional: false {{- else }} value: {{ .Values.global.postgres.master.password | quote}} {{- end }} - name: PGUSER + {{- if $.Values.global.postgres.externalSecret }} + valueFrom: + secretKeyRef: + name: {{ $.Values.global.postgres.externalSecret }} + key: username + optional: false + {{- else }} value: {{ .Values.global.postgres.master.username | quote }} + {{- end }} - name: PGPORT + {{- if $.Values.global.postgres.externalSecret }} + valueFrom: + secretKeyRef: + name: {{ $.Values.global.postgres.externalSecret }} + key: port + optional: false + {{- else }} value: {{ .Values.global.postgres.master.port | quote }} + {{- end }} - name: PGHOST {{- if $.Values.global.dev }} value: "{{ .Release.Name }}-postgresql" + {{- else if $.Values.global.postgres.externalSecret }} + valueFrom: + secretKeyRef: + name: {{ $.Values.global.postgres.externalSecret }} + key: host + optional: false {{- else }} value: {{ .Values.global.postgres.master.host | quote }} {{- end }} @@ -133,6 +162,7 @@ spec: # Update secret to signal that db has been created, and services can start kubectl patch secret/{{ .Chart.Name }}-dbcreds -p '{"data":{"dbcreated":"dHJ1ZQo="}}' fi +{{- end}} {{- end }} @@ -141,6 +171,7 @@ Create k8s secrets for connecting to postgres */}} # DB Secrets {{- define "common.db-secret" -}} +{{- if or (not .Values.global.externalSecrets.deploy) (and .Values.global.externalSecrets.deploy .Values.global.externalSecrets.dbCreate) }} apiVersion: v1 kind: Secret metadata: @@ -155,4 +186,5 @@ data: {{- else }} host: {{ ( $.Values.postgres.host | default ( $.Values.global.postgres.master.host)) | b64enc | quote }} {{- end }} +{{- end }} {{- end }} \ No newline at end of file diff --git a/helm/common/templates/_es_index_restore.tpl b/helm/common/templates/_es_index_restore.tpl index c0c927a1..c3781c0e 100644 --- a/helm/common/templates/_es_index_restore.tpl +++ b/helm/common/templates/_es_index_restore.tpl @@ -21,7 +21,7 @@ spec: volumes: - name: cred-volume secret: - secretName: aws-config-{{ .Chart.Name }} + secretName: {{.Chart.Name}}-aws-config containers: - name: create-indices image: quay.io/cdis/awshelper:master diff --git a/helm/common/templates/_external_secrets.tpl b/helm/common/templates/_external_secrets.tpl new file mode 100644 index 00000000..d684ceed --- /dev/null +++ b/helm/common/templates/_external_secrets.tpl @@ -0,0 +1,87 @@ +{{/* + Service DB Creds Secrets Manager Name +*/}} +{{- define "common.externalSecret.dbcreds.name" -}} +{{- if .Values.externalSecrets.dbcreds }} + {{- default .Values.externalSecrets.dbcreds }} +{{- else }} + {{- .Values.global.environment }}- {{- .Chart.Name }}-creds +{{- end -}} +{{- end -}} + + + + +{{/* + ExternalSecrets Object +*/}} +{{- define "common.externalSecret.db" -}} +{{ if .Values.global.externalSecrets.deploy }} +apiVersion: external-secrets.io/v1beta1 +kind: ExternalSecret +metadata: + name: {{ $.Chart.Name }}-dbcreds +spec: + refreshInterval: 5m + secretStoreRef: + name: {{include "common.SecretStore" .}} + kind: SecretStore + target: + name: {{ $.Chart.Name }}-dbcreds + creationPolicy: Owner + dataFrom: + - extract: + key: {{include "common.externalSecret.dbcreds.name" .}} + conversionStrategy: Default + decodingStrategy: None +{{- end }} +{{- end -}} + + +{{/* + External Secrets Secret Store will allow all charts to allow for authentication to AWS Secrets Manager +*/}} +{{ define "common.secretstore" -}} +apiVersion: external-secrets.io/v1beta1 +kind: SecretStore +metadata: + name: {{.Chart.Name}}-secret-store +spec: + provider: + aws: + service: SecretsManager + region: {{ .Values.global.aws.region }} + auth: + {{- if .Values.global.aws.secretStoreServiceAccount.enabled }} + jwt: + serviceAccountRef: + name: {{ .Values.global.aws.secretStoreServiceAccount.name }} + {{- else }} + secretRef: + accessKeyIDSecretRef: + name: {{.Chart.Name}}-aws-config + key: access-key + secretAccessKeySecretRef: + name: {{.Chart.Name}}-aws-config + key: secret-access-key + {{- end}} +{{- end }} + + + +{{/* + # Name of the SecretStore + # We want to allow override here, in case a chart is being deployed without the umbrella chart, + # or any other needs to deploy a separate secret store per service. +*/}} + +{{/* + Cluster Secret Store for External Secrets +*/}} +{{- define "common.SecretStore" -}} +{{- if .Values.global.externalSecrets.separateSecretStore }} + {{- .Chart.Name }}-secret-store +{{- else }} +{{- default "gen3-secret-store"}} +{{- end -}} +{{- end -}} diff --git a/helm/common/templates/_restore_pgdump.tpl b/helm/common/templates/_restore_pgdump.tpl index 7f849e0c..dffa024d 100644 --- a/helm/common/templates/_restore_pgdump.tpl +++ b/helm/common/templates/_restore_pgdump.tpl @@ -17,7 +17,12 @@ spec: volumes: - name: cred-volume secret: - secretName: aws-config + secretName: {{.Chart.Name}}-aws-config + {{- if .Values.global.aws.useLocalSecret.enabled -}} + secretName: {{ .Values.global.aws.useLocalSecret.localSecretName }} + {{ else }} + secretName: {{.Chart.Name}}-aws-config + {{ end }} containers: - name: restore-dbs image: quay.io/cdis/awshelper:master diff --git a/helm/common/values.yaml b/helm/common/values.yaml index d61b0b39..51b8616b 100644 --- a/helm/common/values.yaml +++ b/helm/common/values.yaml @@ -2,14 +2,21 @@ # This is a YAML-formatted file. # Declare variables to be passed into your templates. -# -- (map) Global configuration options. + +# Global configuration global: + # -- (map) AWS configuration + aws: + # -- (string) AWS region for this deployment + region: us-east-1 # -- (bool) Whether the deployment is for development purposes. dev: true - # -- (map) Postgres database configuration. + postgres: # -- (bool) Whether the database should be created. dbCreate: true + # -- (string) Name of external secret. Disabled if empty + externalSecret: "" # -- (map) Master credentials to postgres. This is going to be the default postgres server being used for each service, unless each service specifies their own postgres master: # -- (string) hostname of postgres server @@ -41,6 +48,6 @@ global: # -- (bool) Whether network policies are enabled. netPolicy: true # -- (int) Number of dispatcher jobs. - dispatcherJobNum: 10 + dispatcherJobNum: "10" # -- (bool) Whether Datadog is enabled. ddEnabled: false diff --git a/helm/dicom-server/Chart.yaml b/helm/dicom-server/Chart.yaml index 5605eab7..4741141b 100644 --- a/helm/dicom-server/Chart.yaml +++ b/helm/dicom-server/Chart.yaml @@ -15,7 +15,7 @@ type: application # This is the chart version. This version number should be incremented each time you make changes # to the chart and its templates, including the app version. # Versions are expected to follow Semantic Versioning (https://semver.org/) -version: 0.1.6 +version: 0.1.8 # This is the version number of the application being deployed. This version number should be # incremented each time you make changes to the application. Versions are not expected to @@ -25,5 +25,5 @@ appVersion: "master" dependencies: - name: common - version: 0.1.8 + version: 0.1.10 repository: file://../common diff --git a/helm/dicom-server/README.md b/helm/dicom-server/README.md index fd8c52f9..f95924f0 100644 --- a/helm/dicom-server/README.md +++ b/helm/dicom-server/README.md @@ -1,6 +1,6 @@ # dicom-server -![Version: 0.1.6](https://img.shields.io/badge/Version-0.1.6-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: master](https://img.shields.io/badge/AppVersion-master-informational?style=flat-square) +![Version: 0.1.8](https://img.shields.io/badge/Version-0.1.8-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: master](https://img.shields.io/badge/AppVersion-master-informational?style=flat-square) A Helm chart for gen3 Dicom Server @@ -8,7 +8,7 @@ A Helm chart for gen3 Dicom Server | Repository | Name | Version | |------------|------|---------| -| file://../common | common | 0.1.8 | +| file://../common | common | 0.1.10 | ## Values @@ -24,7 +24,6 @@ A Helm chart for gen3 Dicom Server | datadogLogsInjection | bool | `true` | If enabled, the Datadog Agent will automatically inject Datadog-specific metadata into your application logs. | | datadogProfilingEnabled | bool | `true` | If enabled, the Datadog Agent will collect profiling data for your application using the Continuous Profiler. This data can be used to identify performance bottlenecks and optimize your application. | | datadogTraceSampleRate | int | `1` | A value between 0 and 1, that represents the percentage of requests that will be traced. For example, a value of 0.5 means that 50% of requests will be traced. | -| global | map | `{"ddEnabled":false,"environment":"default","minAvialable":1,"pdb":false}` | Global configuration options. | | global.ddEnabled | bool | `false` | Whether Datadog is enabled. | | global.environment | string | `"default"` | Environment name. This should be the same as vpcname if you're doing an AWS deployment. Currently this is being used to share ALB's if you have multiple namespaces. Might be used other places too. | | global.minAvialable | int | `1` | The minimum amount of pods that are available at all times if the PDB is deployed. | @@ -54,5 +53,3 @@ A Helm chart for gen3 Dicom Server | volumeMounts | list | `[{"mountPath":"/etc/orthanc/orthanc_config_overwrites.json","name":"config-volume-g3auto","readOnly":true,"subPath":"orthanc_config_overwrites.json"}]` | Volumes to mount to the pod. | | volumes | list | `[{"name":"config-volume-g3auto","secret":{"secretName":"orthanc-g3auto"}}]` | Volumes to attach to the pod. | ----------------------------------------------- -Autogenerated from chart metadata using [helm-docs v1.11.0](https://github.com/norwoodj/helm-docs/releases/v1.11.0) diff --git a/helm/dicom-server/values.yaml b/helm/dicom-server/values.yaml index d4dcdcc7..3cf06900 100644 --- a/helm/dicom-server/values.yaml +++ b/helm/dicom-server/values.yaml @@ -2,7 +2,8 @@ # This is a YAML-formatted file. # Declare variables to be passed into your templates. -# -- (map) Global configuration options. + +# Global configuration global: # -- (string) Environment name. This should be the same as vpcname if you're doing an AWS deployment. Currently this is being used to share ALB's if you have multiple namespaces. Might be used other places too. environment: default diff --git a/helm/dicom-viewer/Chart.yaml b/helm/dicom-viewer/Chart.yaml index dd84c125..4835cfea 100644 --- a/helm/dicom-viewer/Chart.yaml +++ b/helm/dicom-viewer/Chart.yaml @@ -15,7 +15,7 @@ type: application # This is the chart version. This version number should be incremented each time you make changes # to the chart and its templates, including the app version. # Versions are expected to follow Semantic Versioning (https://semver.org/) -version: 0.1.6 +version: 0.1.8 # This is the version number of the application being deployed. This version number should be # incremented each time you make changes to the application. Versions are not expected to @@ -25,5 +25,5 @@ appVersion: "master" dependencies: - name: common - version: 0.1.8 + version: 0.1.10 repository: file://../common diff --git a/helm/dicom-viewer/README.md b/helm/dicom-viewer/README.md index 78ea3e63..28eec517 100644 --- a/helm/dicom-viewer/README.md +++ b/helm/dicom-viewer/README.md @@ -1,6 +1,6 @@ # dicom-viewer -![Version: 0.1.6](https://img.shields.io/badge/Version-0.1.6-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: master](https://img.shields.io/badge/AppVersion-master-informational?style=flat-square) +![Version: 0.1.8](https://img.shields.io/badge/Version-0.1.8-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: master](https://img.shields.io/badge/AppVersion-master-informational?style=flat-square) A Helm chart for gen3 Dicom Viewer @@ -8,7 +8,7 @@ A Helm chart for gen3 Dicom Viewer | Repository | Name | Version | |------------|------|---------| -| file://../common | common | 0.1.8 | +| file://../common | common | 0.1.10 | ## Values @@ -24,7 +24,6 @@ A Helm chart for gen3 Dicom Viewer | datadogLogsInjection | bool | `true` | If enabled, the Datadog Agent will automatically inject Datadog-specific metadata into your application logs. | | datadogProfilingEnabled | bool | `true` | If enabled, the Datadog Agent will collect profiling data for your application using the Continuous Profiler. This data can be used to identify performance bottlenecks and optimize your application. | | datadogTraceSampleRate | int | `1` | A value between 0 and 1, that represents the percentage of requests that will be traced. For example, a value of 0.5 means that 50% of requests will be traced. | -| global | map | `{"ddEnabled":false,"environment":"default","minAvialable":1,"pdb":false}` | Global configuration options. | | global.ddEnabled | bool | `false` | Whether Datadog is enabled. | | global.environment | string | `"default"` | Environment name. This should be the same as vpcname if you're doing an AWS deployment. Currently this is being used to share ALB's if you have multiple namespaces. Might be used other places too. | | global.minAvialable | int | `1` | The minimum amount of pods that are available at all times if the PDB is deployed. | @@ -41,5 +40,3 @@ A Helm chart for gen3 Dicom Viewer | service.port | int | `80` | The port number that the service exposes. | | service.type | string | `"ClusterIP"` | Type of service. Valid values are "ClusterIP", "NodePort", "LoadBalancer", "ExternalName". | ----------------------------------------------- -Autogenerated from chart metadata using [helm-docs v1.11.0](https://github.com/norwoodj/helm-docs/releases/v1.11.0) diff --git a/helm/dicom-viewer/values.yaml b/helm/dicom-viewer/values.yaml index 0fa31147..01c3995b 100644 --- a/helm/dicom-viewer/values.yaml +++ b/helm/dicom-viewer/values.yaml @@ -2,7 +2,8 @@ # This is a YAML-formatted file. # Declare variables to be passed into your templates. -# -- (map) Global configuration options. + +# Global configuration global: # -- (string) Environment name. This should be the same as vpcname if you're doing an AWS deployment. Currently this is being used to share ALB's if you have multiple namespaces. Might be used other places too. environment: default diff --git a/helm/etl/Chart.yaml b/helm/etl/Chart.yaml index 0f9e2fb9..c5b08a7b 100644 --- a/helm/etl/Chart.yaml +++ b/helm/etl/Chart.yaml @@ -15,7 +15,7 @@ type: application # This is the chart version. This version number should be incremented each time you make changes # to the chart and its templates, including the app version. # Versions are expected to follow Semantic Versioning (https://semver.org/) -version: 0.1.0 +version: 0.1.1 # This is the version number of the application being deployed. This version number should be # incremented each time you make changes to the application. Versions are not expected to diff --git a/helm/etl/README.md b/helm/etl/README.md index f874e334..faa4d2f2 100644 --- a/helm/etl/README.md +++ b/helm/etl/README.md @@ -1,6 +1,6 @@ # etl -![Version: 0.1.0](https://img.shields.io/badge/Version-0.1.0-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: master](https://img.shields.io/badge/AppVersion-master-informational?style=flat-square) +![Version: 0.1.1](https://img.shields.io/badge/Version-0.1.1-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: master](https://img.shields.io/badge/AppVersion-master-informational?style=flat-square) A Helm chart for gen3 etl @@ -103,5 +103,3 @@ A Helm chart for gen3 etl | resources.tube.requests.cpu | string | `0.3` | The amount of CPU requested | | resources.tube.requests.memory | string | `"128Mi"` | The amount of memory requested | ----------------------------------------------- -Autogenerated from chart metadata using [helm-docs v1.11.0](https://github.com/norwoodj/helm-docs/releases/v1.11.0) diff --git a/helm/fence/Chart.yaml b/helm/fence/Chart.yaml index d3203de8..b4bd4825 100644 --- a/helm/fence/Chart.yaml +++ b/helm/fence/Chart.yaml @@ -15,7 +15,7 @@ type: application # This is the chart version. This version number should be incremented each time you make changes # to the chart and its templates, including the app version. # Versions are expected to follow Semantic Versioning (https://semver.org/) -version: 0.1.14 +version: 0.1.19 # This is the version number of the application being deployed. This version number should be # incremented each time you make changes to the application. Versions are not expected to @@ -24,7 +24,7 @@ appVersion: "master" dependencies: - name: common - version: 0.1.8 + version: 0.1.11 repository: file://../common - name: postgresql version: 11.9.13 diff --git a/helm/fence/README.md b/helm/fence/README.md index f7d38f0f..796755f5 100644 --- a/helm/fence/README.md +++ b/helm/fence/README.md @@ -1,6 +1,6 @@ # fence -![Version: 0.1.14](https://img.shields.io/badge/Version-0.1.14-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: master](https://img.shields.io/badge/AppVersion-master-informational?style=flat-square) +![Version: 0.1.19](https://img.shields.io/badge/Version-0.1.19-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: master](https://img.shields.io/badge/AppVersion-master-informational?style=flat-square) A Helm chart for gen3 Fence @@ -8,14 +8,14 @@ A Helm chart for gen3 Fence | Repository | Name | Version | |------------|------|---------| -| file://../common | common | 0.1.8 | +| file://../common | common | 0.1.11 | | https://charts.bitnami.com/bitnami | postgresql | 11.9.13 | ## Values | Key | Type | Default | Description | |-----|------|---------|-------------| -| FENCE_CONFIG | map | `{"ACCESS_TOKEN_COOKIE_NAME":"access_token","ACCESS_TOKEN_EXPIRES_IN":1200,"ALLOWED_USER_SERVICE_ACCOUNT_DOMAINS":["developer.gserviceaccount.com","appspot.gserviceaccount.com","iam.gserviceaccount.com"],"ALLOW_GOOGLE_LINKING":true,"APPLICATION_ROOT":"/user","APP_NAME":"Gen3 Data Commons","ARBORIST":"http://arborist-service","ASSUME_ROLE_CACHE_SECONDS":1800,"AUDIT_SERVICE":"http://audit-service","AUTHLIB_INSECURE_TRANSPORT":true,"AWS_CREDENTIALS":{},"AZ_BLOB_CONTAINER_URL":"https://myfakeblob.blob.core.windows.net/my-fake-container/","AZ_BLOB_CREDENTIALS":null,"BILLING_PROJECT_FOR_SA_CREDS":null,"BILLING_PROJECT_FOR_SIGNED_URLS":null,"CIRRUS_CFG":{"GOOGLE_ADMIN_EMAIL":"","GOOGLE_API_KEY":"","GOOGLE_APPLICATION_CREDENTIALS":"","GOOGLE_CLOUD_IDENTITY_ADMIN_EMAIL":"","GOOGLE_IDENTITY_DOMAIN":"","GOOGLE_PROJECT_ID":"","GOOGLE_STORAGE_CREDS":""},"CLIENT_ALLOWED_SCOPES":["openid","user","data","google_credentials","google_service_account","google_link","ga4gh_passport_v1"],"DATA_UPLOAD_BUCKET":"bucket1","DBGAP_ACCESSION_WITH_CONSENT_REGEX":"(?Pphs[0-9]+)(.(?Pv[0-9]+)){0,1}(.(?Pp[0-9]+)){0,1}.(?Pc[0-9]+)","DEBUG":false,"DEFAULT_LOGIN_IDP":"google","DEFAULT_LOGIN_URL":"{{BASE_URL}}/login/google","DEV_LOGIN_COOKIE_NAME":"dev_login","DREAM_CHALLENGE_GROUP":"DREAM","DREAM_CHALLENGE_TEAM":"DREAM","EMAIL_SERVER":"localhost","ENABLED_IDENTITY_PROVIDERS":{},"ENABLE_AUDIT_LOGS":{"login":false,"presigned_url":false},"ENABLE_AUTOMATIC_BILLING_PERMISSION_SA_CREDS":false,"ENABLE_AUTOMATIC_BILLING_PERMISSION_SIGNED_URLS":false,"ENABLE_CSRF_PROTECTION":true,"ENABLE_DB_MIGRATION":true,"ENABLE_PROMETHEUS_METRICS":false,"ENCRYPTION_KEY":"REPLACEME","GA4GH_VISA_ISSUER_ALLOWLIST":["{{BASE_URL}}","https://sts.nih.gov","https://stsstg.nih.gov"],"GEN3_PASSPORT_EXPIRES_IN":43200,"GLOBAL_PARSE_VISAS_ON_LOGIN":false,"GOOGLE_ACCOUNT_ACCESS_EXPIRES_IN":86400,"GOOGLE_BULK_UPDATES":false,"GOOGLE_GROUP_PREFIX":"","GOOGLE_MANAGED_SERVICE_ACCOUNT_DOMAINS":["dataflow-service-producer-prod.iam.gserviceaccount.com","cloudbuild.gserviceaccount.com","cloud-ml.google.com.iam.gserviceaccount.com","container-engine-robot.iam.gserviceaccount.com","dataflow-service-producer-prod.iam.gserviceaccount.com","sourcerepo-service-accounts.iam.gserviceaccount.com","dataproc-accounts.iam.gserviceaccount.com","gae-api-prod.google.com.iam.gserviceaccount.com","genomics-api.google.com.iam.gserviceaccount.com","containerregistry.iam.gserviceaccount.com","container-analysis.iam.gserviceaccount.com","cloudservices.gserviceaccount.com","stackdriver-service.iam.gserviceaccount.com","appspot.gserviceaccount.com","partnercontent.gserviceaccount.com","trifacta-gcloud-prod.iam.gserviceaccount.com","gcf-admin-robot.iam.gserviceaccount.com","compute-system.iam.gserviceaccount.com","gcp-sa-websecurityscanner.iam.gserviceaccount.com","storage-transfer-service.iam.gserviceaccount.com","firebase-sa-management.iam.gserviceaccount.com","firebase-rules.iam.gserviceaccount.com","gcp-sa-cloudbuild.iam.gserviceaccount.com","gcp-sa-automl.iam.gserviceaccount.com","gcp-sa-datalabeling.iam.gserviceaccount.com","gcp-sa-cloudscheduler.iam.gserviceaccount.com"],"GOOGLE_SERVICE_ACCOUNT_KEY_FOR_URL_SIGNING_EXPIRES_IN":2592000,"GOOGLE_SERVICE_ACCOUNT_PREFIX":"","GOOGLE_USER_SERVICE_ACCOUNT_ACCESS_EXPIRES_IN":604800,"GUN_MAIL":{"datacommons.io":{"api_key":"","api_url":"https://api.mailgun.net/v3/mailgun.example.com","default_login":"postmaster@mailgun.example.com","smtp_hostname":"smtp.mailgun.org","smtp_password":""}},"HTTP_PROXY":{"host":null,"port":3128},"INDEXD":"http://indexd-service","INDEXD_PASSWORD":"","INDEXD_USERNAME":"fence","ITRUST_GLOBAL_LOGOUT":"https://auth.nih.gov/siteminderagent/smlogout.asp?mode=nih&AppReturnUrl=","LOGIN_OPTIONS":[{"desc":"description","idp":"google","name":"Login from Google"}],"LOGIN_REDIRECT_WHITELIST":[],"MAX_ACCESS_TOKEN_TTL":3600,"MAX_API_KEY_TTL":2592000,"MAX_PRESIGNED_URL_TTL":3600,"MAX_ROLE_SESSION_INCREASE":false,"MOCK_AUTH":false,"MOCK_GOOGLE_AUTH":false,"MOCK_STORAGE":false,"OAUTH2_JWT_ALG":"RS256","OAUTH2_JWT_ENABLED":true,"OAUTH2_JWT_ISS":"{{BASE_URL}}","OAUTH2_PROVIDER_ERROR_URI":"/api/oauth2/errors","OAUTH2_TOKEN_EXPIRES_IN":{"authorization_code":1200,"implicit":1200},"OPENID_CONNECT":{"cilogon":{"client_id":"","client_secret":"","discovery_url":"https://cilogon.org/.well-known/openid-configuration","mock":false,"mock_default_user":"http://cilogon.org/serverT/users/64703","redirect_url":"{{BASE_URL}}/login/cilogon/login/","scope":"openid email profile"},"cognito":{"client_id":"","client_secret":"","discovery_url":"https://cognito-idp.{REGION}.amazonaws.com/{USER-POOL-ID}/.well-known/openid-configuration","redirect_url":"{{BASE_URL}}/login/cognito/login/","scope":"openid email"},"fence":{"access_token_url":"{{api_base_url}}/oauth2/token","api_base_url":"","authorize_url":"{{api_base_url}}/oauth2/authorize","client_id":"","client_kwargs":{"redirect_uri":"{{BASE_URL}}/login/fence/login","scope":"openid"},"client_secret":"","mock":false,"mock_default_user":"test@example.com","name":"","refresh_token_url":"{{api_base_url}}/oauth2/token","shibboleth_discovery_url":"https://login.bionimbus.org/Shibboleth.sso/DiscoFeed"},"generic_oidc_idp":{"client_id":"","client_secret":"","discovery":{"authorization_endpoint":"","jwks_uri":"","token_endpoint":""},"discovery_url":"https://server.com/.well-known/openid-configuration","email_field":"","name":"some_idp","redirect_url":"{{BASE_URL}}/login/some_idp/login","scope":"","user_id_field":""},"google":{"client_id":"","client_secret":"","discovery_url":"https://accounts.google.com/.well-known/openid-configuration","mock":"","mock_default_user":"test@example.com","redirect_url":"{{BASE_URL}}/login/google/login/","scope":"openid email"},"microsoft":{"client_id":"","client_secret":"","discovery_url":"https://login.microsoftonline.com/organizations/v2.0/.well-known/openid-configuration","mock":false,"mock_default_user":"test@example.com","redirect_url":"{{BASE_URL}}/login/microsoft/login/","scope":"openid email"},"okta":{"client_id":"","client_secret":"","discovery_url":"","redirect_url":"{{BASE_URL}}/login/okta/login/","scope":"openid email"},"orcid":{"client_id":"","client_secret":"","discovery_url":"https://orcid.org/.well-known/openid-configuration","mock":false,"mock_default_user":"0000-0002-2601-8132","redirect_url":"{{BASE_URL}}/login/orcid/login/","scope":"openid"},"ras":{"client_id":"","client_secret":"","discovery_url":"https://sts.nih.gov/.well-known/openid-configuration","mock":false,"mock_default_user":"test@example.com","redirect_url":"{{BASE_URL}}/login/ras/callback","scope":"openid email profile ga4gh_passport_v1"},"shibboleth":{"client_id":"","client_secret":"","redirect_url":"{{BASE_URL}}/login/shib/login"},"synapse":{"client_id":"","client_secret":"","discovery_url":"","redirect_url":"","scope":"openid"}},"OVERRIDE_NGINX_RATE_LIMIT":18,"PRIVACY_POLICY_URL":null,"PROBLEM_USER_EMAIL_NOTIFICATION":{"admin":["admin@example.edu"],"content":"The Data Commons Framework utilizes dbGaP for data access authorization. Another member of a Google project you belong to ({}) is attempting to register a service account to the following additional datasets ({}). Please contact dbGaP to request access.\n","domain":"example.com","from":"do-not-reply@example.com","subject":"Account access error notification"},"PUSH_AUDIT_LOGS_CONFIG":{"aws_sqs_config":{"aws_cred":null,"region":null,"sqs_url":null},"type":"aws_sqs"},"RAS_REFRESH_EXPIRATION":1296000,"RAS_USERINFO_ENDPOINT":"/openid/connect/v1.1/userinfo","REFRESH_TOKEN_EXPIRES_IN":2592000,"REGISTERED_USERS_GROUP":"","REGISTER_USERS_ON":false,"REMOVE_SERVICE_ACCOUNT_EMAIL_NOTIFICATION":{"admin":["admin@example.edu"],"content":"Service accounts were removed from access control data because some users or service accounts of GCP Project {} are not authorized to access the data sets associated to the service accounts, or do not adhere to the security policies.\n","domain":"example.com","enable":false,"from":"do-not-reply@example.com","subject":"User service account removal notification"},"RENEW_ACCESS_TOKEN_BEFORE_EXPIRATION":false,"S3_BUCKETS":{},"SEND_FROM":"example@gmail.com","SEND_TO":"example@gmail.com","SERVICE_ACCOUNT_LIMIT":6,"SESSION_ALLOWED_SCOPES":["openid","user","credentials","data","admin","google_credentials","google_service_account","google_link","ga4gh_passport_v1"],"SESSION_COOKIE_DOMAIN":null,"SESSION_COOKIE_NAME":"fence","SESSION_COOKIE_SECURE":true,"SESSION_LIFETIME":28800,"SESSION_TIMEOUT":1800,"SHIBBOLETH_HEADER":"persistent_id","SSO_URL":"https://auth.nih.gov/affwebservices/public/saml2sso?SPID={{BASE_URL}}/shibboleth&RelayState=","STORAGE_CREDENTIALS":{},"SUPPORT_EMAIL_FOR_ERRORS":null,"SYNAPSE_AUTHZ_TTL":86400,"SYNAPSE_DISCOVERY_URL":null,"SYNAPSE_JWKS_URI":null,"SYNAPSE_URI":"https://repo-prod.prod.sagebase.org/auth/v1","TOKEN_PROJECTS_CUTOFF":10,"USERSYNC":{"fallback_to_dbgap_sftp":false,"sync_from_visas":false,"visa_types":{"ras":["https://ras.nih.gov/visas/v1","https://ras.nih.gov/visas/v1.1"]}},"USER_ALLOWED_SCOPES":["fence","openid","user","data","admin","google_credentials","google_service_account","google_link","ga4gh_passport_v1"],"WHITE_LISTED_GOOGLE_PARENT_ORGS":[],"WHITE_LISTED_SERVICE_ACCOUNT_EMAILS":[],"WTF_CSRF_SECRET_KEY":"{{ENCRYPTION_KEY}}","dbGaP":[{"decrypt_key":"","enable_common_exchange_area_access":false,"info":{"host":"","password":"","port":22,"proxy":"","username":""},"parse_consent_code":true,"protocol":"sftp","study_common_exchange_areas":{"example":"test_common_exchange_area"},"study_to_resource_namespaces":{"_default":["/"],"test_common_exchange_area":["/dbgap/"]}}]}` | Configuration settings for Fence app | +| FENCE_CONFIG | map | `{"ACCESS_TOKEN_COOKIE_NAME":"access_token","ACCESS_TOKEN_EXPIRES_IN":1200,"ALLOWED_USER_SERVICE_ACCOUNT_DOMAINS":["developer.gserviceaccount.com","appspot.gserviceaccount.com","iam.gserviceaccount.com"],"ALLOW_GOOGLE_LINKING":true,"APPLICATION_ROOT":"/user","APP_NAME":"Gen3 Data Commons","ARBORIST":"http://arborist-service","ASSUME_ROLE_CACHE_SECONDS":1800,"AUDIT_SERVICE":"http://audit-service","AUTHLIB_INSECURE_TRANSPORT":true,"AWS_CREDENTIALS":{},"AZ_BLOB_CONTAINER_URL":"https://myfakeblob.blob.core.windows.net/my-fake-container/","AZ_BLOB_CREDENTIALS":null,"BILLING_PROJECT_FOR_SA_CREDS":null,"BILLING_PROJECT_FOR_SIGNED_URLS":null,"CIRRUS_CFG":{"GOOGLE_ADMIN_EMAIL":"","GOOGLE_API_KEY":"","GOOGLE_APPLICATION_CREDENTIALS":"","GOOGLE_CLOUD_IDENTITY_ADMIN_EMAIL":"","GOOGLE_IDENTITY_DOMAIN":"","GOOGLE_PROJECT_ID":"","GOOGLE_STORAGE_CREDS":""},"CLIENT_ALLOWED_SCOPES":["openid","user","data","google_credentials","google_service_account","google_link","ga4gh_passport_v1"],"DATA_UPLOAD_BUCKET":"bucket1","DBGAP_ACCESSION_WITH_CONSENT_REGEX":"(?Pphs[0-9]+)(.(?Pv[0-9]+)){0,1}(.(?Pp[0-9]+)){0,1}.(?Pc[0-9]+)","DEBUG":false,"DEFAULT_LOGIN_IDP":"google","DEFAULT_LOGIN_URL":"{{BASE_URL}}/login/google","DEV_LOGIN_COOKIE_NAME":"dev_login","DREAM_CHALLENGE_GROUP":"DREAM","DREAM_CHALLENGE_TEAM":"DREAM","EMAIL_SERVER":"localhost","ENABLED_IDENTITY_PROVIDERS":{},"ENABLE_AUDIT_LOGS":{"login":false,"presigned_url":false},"ENABLE_AUTOMATIC_BILLING_PERMISSION_SA_CREDS":false,"ENABLE_AUTOMATIC_BILLING_PERMISSION_SIGNED_URLS":false,"ENABLE_CSRF_PROTECTION":true,"ENABLE_DB_MIGRATION":true,"ENABLE_PROMETHEUS_METRICS":false,"ENCRYPTION_KEY":"REPLACEME","GA4GH_VISA_ISSUER_ALLOWLIST":["{{BASE_URL}}","https://sts.nih.gov","https://stsstg.nih.gov"],"GEN3_PASSPORT_EXPIRES_IN":43200,"GLOBAL_PARSE_VISAS_ON_LOGIN":false,"GOOGLE_ACCOUNT_ACCESS_EXPIRES_IN":86400,"GOOGLE_BULK_UPDATES":false,"GOOGLE_GROUP_PREFIX":"","GOOGLE_MANAGED_SERVICE_ACCOUNT_DOMAINS":["dataflow-service-producer-prod.iam.gserviceaccount.com","cloudbuild.gserviceaccount.com","cloud-ml.google.com.iam.gserviceaccount.com","container-engine-robot.iam.gserviceaccount.com","dataflow-service-producer-prod.iam.gserviceaccount.com","sourcerepo-service-accounts.iam.gserviceaccount.com","dataproc-accounts.iam.gserviceaccount.com","gae-api-prod.google.com.iam.gserviceaccount.com","genomics-api.google.com.iam.gserviceaccount.com","containerregistry.iam.gserviceaccount.com","container-analysis.iam.gserviceaccount.com","cloudservices.gserviceaccount.com","stackdriver-service.iam.gserviceaccount.com","appspot.gserviceaccount.com","partnercontent.gserviceaccount.com","trifacta-gcloud-prod.iam.gserviceaccount.com","gcf-admin-robot.iam.gserviceaccount.com","compute-system.iam.gserviceaccount.com","gcp-sa-websecurityscanner.iam.gserviceaccount.com","storage-transfer-service.iam.gserviceaccount.com","firebase-sa-management.iam.gserviceaccount.com","firebase-rules.iam.gserviceaccount.com","gcp-sa-cloudbuild.iam.gserviceaccount.com","gcp-sa-automl.iam.gserviceaccount.com","gcp-sa-datalabeling.iam.gserviceaccount.com","gcp-sa-cloudscheduler.iam.gserviceaccount.com"],"GOOGLE_SERVICE_ACCOUNT_KEY_FOR_URL_SIGNING_EXPIRES_IN":2592000,"GOOGLE_SERVICE_ACCOUNT_PREFIX":"","GOOGLE_USER_SERVICE_ACCOUNT_ACCESS_EXPIRES_IN":604800,"GUN_MAIL":{"datacommons.io":{"api_key":"","api_url":"https://api.mailgun.net/v3/mailgun.example.com","default_login":"postmaster@mailgun.example.com","smtp_hostname":"smtp.mailgun.org","smtp_password":""}},"HTTP_PROXY":{"host":null,"port":3128},"INDEXD":"http://indexd-service","INDEXD_PASSWORD":"","INDEXD_USERNAME":"fence","ITRUST_GLOBAL_LOGOUT":"https://auth.nih.gov/siteminderagent/smlogout.asp?mode=nih&AppReturnUrl=","LOGIN_OPTIONS":[{"desc":"description","idp":"google","name":"Login from Google"}],"LOGIN_REDIRECT_WHITELIST":[],"MAX_ACCESS_TOKEN_TTL":3600,"MAX_API_KEY_TTL":2592000,"MAX_PRESIGNED_URL_TTL":3600,"MAX_ROLE_SESSION_INCREASE":false,"MOCK_AUTH":false,"MOCK_GOOGLE_AUTH":false,"MOCK_STORAGE":false,"OAUTH2_JWT_ALG":"RS256","OAUTH2_JWT_ENABLED":true,"OAUTH2_JWT_ISS":"{{BASE_URL}}","OAUTH2_PROVIDER_ERROR_URI":"/api/oauth2/errors","OAUTH2_TOKEN_EXPIRES_IN":{"authorization_code":1200,"implicit":1200},"OPENID_CONNECT":{"cilogon":{"client_id":"","client_secret":"","discovery_url":"https://cilogon.org/.well-known/openid-configuration","mock":false,"mock_default_user":"http://cilogon.org/serverT/users/64703","redirect_url":"{{BASE_URL}}/login/cilogon/login/","scope":"openid email profile"},"cognito":{"client_id":"","client_secret":"","discovery_url":"https://cognito-idp.{REGION}.amazonaws.com/{USER-POOL-ID}/.well-known/openid-configuration","redirect_url":"{{BASE_URL}}/login/cognito/login/","scope":"openid email"},"fence":{"access_token_url":"{{api_base_url}}/oauth2/token","api_base_url":"","authorize_url":"{{api_base_url}}/oauth2/authorize","client_id":"","client_kwargs":{"redirect_uri":"{{BASE_URL}}/login/fence/login","scope":"openid"},"client_secret":"","mock":false,"mock_default_user":"test@example.com","name":"","refresh_token_url":"{{api_base_url}}/oauth2/token","shibboleth_discovery_url":"https://login.bionimbus.org/Shibboleth.sso/DiscoFeed"},"generic_oidc_idp":{"client_id":"","client_secret":"","discovery":{"authorization_endpoint":"","jwks_uri":"","token_endpoint":""},"discovery_url":"https://server.com/.well-known/openid-configuration","email_field":"","name":"some_idp","redirect_url":"{{BASE_URL}}/login/some_idp/login","scope":"","user_id_field":""},"google":{"client_id":"","client_secret":"","discovery_url":"https://accounts.google.com/.well-known/openid-configuration","mock":"","mock_default_user":"test@example.com","redirect_url":"{{BASE_URL}}/login/google/login/","scope":"openid email"},"microsoft":{"client_id":"","client_secret":"","discovery_url":"https://login.microsoftonline.com/organizations/v2.0/.well-known/openid-configuration","mock":false,"mock_default_user":"test@example.com","redirect_url":"{{BASE_URL}}/login/microsoft/login/","scope":"openid email"},"okta":{"client_id":"","client_secret":"","discovery_url":"","redirect_url":"{{BASE_URL}}/login/okta/login/","scope":"openid email"},"orcid":{"client_id":"","client_secret":"","discovery_url":"https://orcid.org/.well-known/openid-configuration","mock":false,"mock_default_user":"0000-0002-2601-8132","redirect_url":"{{BASE_URL}}/login/orcid/login/","scope":"openid"},"ras":{"client_id":"","client_secret":"","discovery_url":"https://sts.nih.gov/.well-known/openid-configuration","mock":false,"mock_default_user":"test@example.com","redirect_url":"{{BASE_URL}}/login/ras/callback","scope":"openid email profile ga4gh_passport_v1"},"shibboleth":{"client_id":"","client_secret":"","redirect_url":"{{BASE_URL}}/login/shib/login"},"synapse":{"client_id":"","client_secret":"","discovery_url":"","redirect_url":"","scope":"openid"}},"OVERRIDE_NGINX_RATE_LIMIT":18,"PRIVACY_POLICY_URL":null,"PROBLEM_USER_EMAIL_NOTIFICATION":{"admin":["admin@example.edu"],"content":"The Data Commons Framework utilizes dbGaP for data access authorization. Another member of a Google project you belong to ({}) is attempting to register a service account to the following additional datasets ({}). Please contact dbGaP to request access.\n","domain":"example.com","from":"do-not-reply@example.com","subject":"Account access error notification"},"PUSH_AUDIT_LOGS_CONFIG":{"aws_sqs_config":{"aws_cred":null,"region":null,"sqs_url":null},"type":"aws_sqs"},"RAS_REFRESH_EXPIRATION":1296000,"RAS_USERINFO_ENDPOINT":"/openid/connect/v1.1/userinfo","REFRESH_TOKEN_EXPIRES_IN":2592000,"REGISTERED_USERS_GROUP":"","REGISTER_USERS_ON":false,"REMOVE_SERVICE_ACCOUNT_EMAIL_NOTIFICATION":{"admin":["admin@example.edu"],"content":"Service accounts were removed from access control data because some users or service accounts of GCP Project {} are not authorized to access the data sets associated to the service accounts, or do not adhere to the security policies.\n","domain":"example.com","enable":false,"from":"do-not-reply@example.com","subject":"User service account removal notification"},"RENEW_ACCESS_TOKEN_BEFORE_EXPIRATION":false,"S3_BUCKETS":{},"SEND_FROM":"example@gmail.com","SEND_TO":"example@gmail.com","SERVICE_ACCOUNT_LIMIT":6,"SESSION_ALLOWED_SCOPES":["openid","user","credentials","data","admin","google_credentials","google_service_account","google_link","ga4gh_passport_v1"],"SESSION_COOKIE_DOMAIN":null,"SESSION_COOKIE_NAME":"fence","SESSION_COOKIE_SECURE":true,"SESSION_LIFETIME":28800,"SESSION_TIMEOUT":1800,"SHIBBOLETH_HEADER":"persistent_id","SSO_URL":"https://auth.nih.gov/affwebservices/public/saml2sso?SPID={{BASE_URL}}/shibboleth&RelayState=","STORAGE_CREDENTIALS":{},"SUPPORT_EMAIL_FOR_ERRORS":null,"SYNAPSE_AUTHZ_TTL":86400,"SYNAPSE_DISCOVERY_URL":null,"SYNAPSE_JWKS_URI":null,"SYNAPSE_URI":"https://repo-prod.prod.sagebase.org/auth/v1","TOKEN_PROJECTS_CUTOFF":10,"USERSYNC":{"fallback_to_dbgap_sftp":false,"sync_from_visas":false,"visa_types":{"ras":["https://ras.nih.gov/visas/v1","https://ras.nih.gov/visas/v1.1"]}},"USER_ALLOWED_SCOPES":["fence","openid","user","data","admin","google_credentials","google_service_account","google_link","ga4gh_passport_v1"],"WHITE_LISTED_GOOGLE_PARENT_ORGS":[],"WHITE_LISTED_SERVICE_ACCOUNT_EMAILS":[],"WTF_CSRF_SECRET_KEY":"{{ENCRYPTION_KEY}}","dbGaP":[{"decrypt_key":"","enable_common_exchange_area_access":false,"info":{"host":"","password":"","port":22,"proxy":"","username":""},"parse_consent_code":true,"protocol":"sftp","study_common_exchange_areas":{"example":"test_common_exchange_area"},"study_to_resource_namespaces":{"_default":["/"],"test_common_exchange_area":["/dbgap/"]}}]}` | Private configuration settings for Fence app | | FENCE_CONFIG.APP_NAME | string | `"Gen3 Data Commons"` | Name of the Fence app | | FENCE_CONFIG.AUTHLIB_INSECURE_TRANSPORT | bool | `true` | allow OIDC traffic on http for development. By default it requires https. WARNING: ONLY set to true when fence will be deployed in such a way that it will ONLY receive traffic from internal clients and can safely use HTTP. | | FENCE_CONFIG.CLIENT_ALLOWED_SCOPES | list | `["openid","user","data","google_credentials","google_service_account","google_link","ga4gh_passport_v1"]` | These are the *possible* scopes a client can be given, NOT scopes that are given to all clients. You can be more restrictive during client creation | @@ -69,6 +69,7 @@ A Helm chart for gen3 Fence | FENCE_CONFIG.SESSION_COOKIE_SECURE | bool | `true` | set if you want browsers to only send cookies with requests over HTTPS | | FENCE_CONFIG.USER_ALLOWED_SCOPES | list | `["fence","openid","user","data","admin","google_credentials","google_service_account","google_link","ga4gh_passport_v1"]` | these are the scopes that CAN be included in a user's own access_token | | FENCE_CONFIG.WTF_CSRF_SECRET_KEY | str | `"{{ENCRYPTION_KEY}}"` | signing key for WTForms to sign CSRF tokens with | +| FENCE_CONFIG_PUBLIC | map | `{}` | Public configuration settings for Fence app | | USER_YAML | string | `"cloud_providers: {}\ngroups: {}\nauthz:\n # policies automatically given to anyone, even if they haven't authenticated\n anonymous_policies: ['open_data_reader', 'full_open_access']\n\n # policies automatically given to authenticated users (in addition to their other\n # policies)\n all_users_policies: ['open_data_reader', 'authn_open_access']\n\n user_project_to_resource:\n QA: /programs/QA\n DEV: /programs/DEV\n test: /programs/QA/projects/test\n jenkins: /programs/jnkns/projects/jenkins\n jenkins2: /programs/jnkns/projects/jenkins2\n jnkns: /programs/jnkns\n\n policies:\n # General Access\n - id: 'workspace'\n description: 'be able to use workspace'\n resource_paths: ['/workspace']\n role_ids: ['workspace_user']\n - id: 'dashboard'\n description: 'be able to use the commons dashboard'\n resource_paths: ['/dashboard']\n role_ids: ['dashboard_user']\n - id: 'prometheus'\n description: 'be able to use prometheus'\n resource_paths: ['/prometheus']\n role_ids: ['prometheus_user']\n - id: 'ttyadmin'\n description: 'be able to use the admin tty'\n resource_paths: ['/ttyadmin']\n role_ids: ['ttyadmin_user']\n - id: 'mds_admin'\n description: 'be able to use metadata service'\n resource_paths: ['/mds_gateway']\n role_ids: ['mds_user']\n - id: 'data_upload'\n description: 'upload raw data files to S3'\n role_ids: ['file_uploader']\n resource_paths: ['/data_file']\n - description: be able to use sower job\n id: sower\n resource_paths: [/sower]\n role_ids: [sower_user]\n - id: 'mariner_admin'\n description: 'full access to mariner API'\n resource_paths: ['/mariner']\n role_ids: ['mariner_admin']\n - id: audit_reader\n role_ids:\n - audit_reader\n resource_paths:\n - /services/audit\n - id: audit_login_reader\n role_ids:\n - audit_reader\n resource_paths:\n - /services/audit/login\n - id: audit_presigned_url_reader\n role_ids:\n - audit_reader\n resource_paths:\n - /services/audit/presigned_url\n - id: requestor_admin\n role_ids:\n - requestor_admin\n resource_paths:\n - /programs\n - id: requestor_reader\n role_ids:\n - requestor_reader\n resource_paths:\n - /programs\n - id: requestor_creator\n role_ids:\n - requestor_creator\n resource_paths:\n - /programs\n - id: requestor_updater\n role_ids:\n - requestor_updater\n resource_paths:\n - /programs\n - id: requestor_deleter\n role_ids:\n - requestor_deleter\n resource_paths:\n - /programs\n # Data Access\n\n # All programs policy\n - id: 'all_programs_reader'\n description: ''\n role_ids:\n - 'reader'\n - 'storage_reader'\n resource_paths: ['/programs']\n\n # # example if need access to write to storage\n # - id: 'programs.jnkns-storage_writer'\n # description: ''\n # role_ids:\n # - 'storage_writer'\n # resource_paths: ['/programs/jnkns']\n\n - id: 'programs.jnkns-admin'\n description: ''\n role_ids:\n - 'creator'\n - 'reader'\n - 'updater'\n - 'deleter'\n - 'storage_reader'\n resource_paths:\n - '/programs/jnkns'\n - '/gen3/programs/jnkns'\n\n - id: 'programs.jnkns-viewer'\n description: ''\n role_ids:\n - 'reader'\n - 'storage_reader'\n resource_paths:\n - '/programs/jnkns'\n - '/gen3/programs/jnkns'\n\n\n - id: 'programs.QA-admin'\n description: ''\n role_ids:\n - 'creator'\n - 'reader'\n - 'updater'\n - 'deleter'\n - 'storage_reader'\n resource_paths:\n - '/programs/QA'\n - '/gen3/programs/QA'\n\n - id: 'programs.QA-admin-no-storage'\n description: ''\n role_ids:\n - 'creator'\n - 'reader'\n - 'updater'\n - 'deleter'\n resource_paths:\n - '/programs/QA'\n - '/gen3/programs/QA'\n\n - id: 'programs.QA-viewer'\n description: ''\n role_ids:\n - 'reader'\n - 'storage_reader'\n resource_paths:\n - '/programs/QA'\n - '/gen3/programs/QA'\n\n - id: 'programs.DEV-admin'\n description: ''\n role_ids:\n - 'creator'\n - 'reader'\n - 'updater'\n - 'deleter'\n - 'storage_reader'\n - 'storage_writer'\n resource_paths:\n - '/programs/DEV'\n - '/gen3/programs/DEV'\n\n - id: 'programs.DEV-storage_writer'\n description: ''\n role_ids:\n - 'storage_writer'\n resource_paths: ['/programs/DEV']\n\n - id: 'programs.DEV-viewer'\n description: ''\n role_ids:\n - 'reader'\n - 'storage_reader'\n resource_paths:\n - '/programs/DEV'\n - '/gen3/programs/DEV'\n\n - id: 'programs.test-admin'\n description: ''\n role_ids:\n - 'creator'\n - 'reader'\n - 'updater'\n - 'deleter'\n - 'storage_reader'\n resource_paths:\n - '/programs/test'\n - '/gen3/programs/test'\n\n - id: 'programs.test-viewer'\n description: ''\n role_ids:\n - 'reader'\n - 'storage_reader'\n resource_paths:\n - '/programs/test'\n - '/gen3/programs/test'\n\n - id: 'abc-admin'\n description: ''\n role_ids:\n - 'creator'\n - 'reader'\n - 'updater'\n - 'deleter'\n - 'storage_reader'\n resource_paths:\n - '/abc'\n\n - id: 'gen3-admin'\n description: ''\n role_ids:\n - 'creator'\n - 'reader'\n - 'updater'\n - 'deleter'\n - 'storage_reader'\n resource_paths:\n - '/gen3'\n\n - id: 'gen3-hmb-researcher'\n description: ''\n role_ids:\n - 'creator'\n - 'reader'\n - 'updater'\n - 'deleter'\n - 'storage_reader'\n resource_paths:\n - '/consents/NRES'\n - '/consents/GRU'\n - '/consents/GRU_CC'\n - '/consents/HMB'\n - '/gen3'\n\n - id: 'abc.programs.test_program.projects.test_project1-viewer'\n description: ''\n role_ids:\n - 'reader'\n - 'storage_reader'\n resource_paths:\n - '/abc/programs/test_program/projects/test_project1'\n\n - id: 'abc.programs.test_program.projects.test_project2-viewer'\n description: ''\n role_ids:\n - 'reader'\n - 'storage_reader'\n resource_paths:\n - '/abc/programs/test_program/projects/test_project2'\n\n - id: 'abc.programs.test_program2.projects.test_project3-viewer'\n description: ''\n role_ids:\n - 'reader'\n - 'storage_reader'\n resource_paths:\n - '/abc/programs/test_program2/projects/test_project3'\n\n # Open data policies\n - id: 'authn_open_access'\n resource_paths: ['/programs/open/projects/authnRequired']\n description: ''\n role_ids:\n - 'reader'\n - 'storage_reader'\n - id: 'full_open_access'\n resource_paths: ['/programs/open/projects/1000G']\n description: ''\n role_ids:\n - 'reader'\n - 'storage_reader'\n - id: 'open_data_reader'\n description: ''\n role_ids:\n - 'reader'\n - 'storage_reader'\n resource_paths: ['/open']\n - id: 'open_data_admin'\n description: ''\n role_ids:\n - 'creator'\n - 'reader'\n - 'updater'\n - 'deleter'\n - 'storage_writer'\n - 'storage_reader'\n resource_paths: ['/open']\n\n # Consent Code Policies\n - id: 'not-for-profit-researcher'\n description: ''\n role_ids:\n - 'admin'\n resource_paths:\n - '/consents/NPU'\n\n - id: 'publication-required-researcher'\n description: ''\n role_ids:\n - 'admin'\n resource_paths:\n - '/consents/PUB'\n\n - id: 'gru-researcher'\n description: ''\n role_ids:\n - 'admin'\n resource_paths:\n - '/consents/NRES'\n - '/consents/GRU'\n\n - id: 'gru-cc-researcher'\n description: ''\n role_ids:\n - 'admin'\n resource_paths:\n - '/consents/NRES'\n - '/consents/GRU'\n - '/consents/GRU_CC'\n\n - id: 'hmb-researcher'\n description: ''\n role_ids:\n - 'admin'\n resource_paths:\n - '/consents/NRES'\n - '/consents/GRU'\n - '/consents/GRU_CC'\n - '/consents/HMB'\n\n - id: 'poa-researcher'\n description: ''\n role_ids:\n - 'admin'\n resource_paths:\n - '/consents/NRES'\n - '/consents/GRU'\n - '/consents/GRU_CC'\n - '/consents/POA'\n\n - id: 'ds-lung-researcher'\n description: ''\n role_ids:\n - 'admin'\n resource_paths:\n - '/consents/NRES'\n - '/consents/GRU'\n - '/consents/GRU_CC'\n - '/consents/HMB'\n - '/consents/DS_LungDisease'\n\n - id: 'ds-chronic-obstructive-pulmonary-disease-researcher'\n description: ''\n role_ids:\n - 'admin'\n resource_paths:\n - '/consents/NRES'\n - '/consents/GRU'\n - '/consents/GRU_CC'\n - '/consents/HMB'\n - '/consents/DS_ChronicObstructivePulmonaryDisease'\n\n - id: 'services.sheepdog-admin'\n description: 'CRUD access to programs and projects'\n role_ids:\n - 'sheepdog_admin'\n resource_paths:\n - '/services/sheepdog/submission/program'\n - '/services/sheepdog/submission/project'\n\n # indexd\n - id: 'indexd_admin'\n description: 'full access to indexd API'\n role_ids:\n - 'indexd_admin'\n resource_paths:\n - '/programs'\n - '/services/indexd/admin'\n # # TODO resource path '/' is not valid right now in arborist, trying to decide\n # # how to handle all resources\n # - id: 'indexd_admin'\n # description: ''\n # role_ids:\n # - 'indexd_record_creator'\n # - 'indexd_record_reader'\n # - 'indexd_record_updater'\n # - 'indexd_delete_record'\n # - 'indexd_storage_reader'\n # - 'indexd_storage_writer'\n # resource_paths: ['/']\n # - id: 'indexd_record_reader'\n # description: ''\n # role_ids:\n # - 'indexd_record_reader'\n # resource_paths: ['/']\n # - id: 'indexd_record_editor'\n # description: ''\n # role_ids:\n # - 'indexd_record_creator'\n # - 'indexd_record_reader'\n # - 'indexd_record_updater'\n # - 'indexd_delete_record'\n # resource_paths: ['/']\n # - id: 'indexd_storage_reader'\n # description: ''\n # role_ids:\n # - 'indexd_storage_reader'\n # resource_paths: ['/']\n # - id: 'indexd_storage_editor'\n # description: ''\n # role_ids:\n # - 'indexd_storage_reader'\n # - 'indexd_storage_writer'\n # resource_paths: ['/']\n\n # argo\n - id: argo\n description: be able to use argo\n resource_paths: [/argo]\n role_ids: [argo_user]\n\n resources:\n # General Access\n - name: 'data_file'\n description: 'data files, stored in S3'\n - name: 'dashboard'\n description: 'commons /dashboard'\n - name: 'mds_gateway'\n description: 'commons /mds-admin'\n - name: 'prometheus'\n description: 'commons /prometheus and /grafana'\n - name: 'ttyadmin'\n description: 'commons /ttyadmin'\n - name: 'workspace'\n - name: \"sower\"\n - name: 'mariner'\n description: 'workflow execution service'\n - name: argo\n\n # OLD Data\n - name: 'programs'\n subresources:\n - name: 'open'\n subresources:\n - name: 'projects'\n subresources:\n - name: '1000G'\n - name: 'authnRequired'\n - name: 'QA'\n subresources:\n - name: 'projects'\n subresources:\n - name: 'test'\n - name: 'DEV'\n subresources:\n - name: 'projects'\n subresources:\n - name: 'test'\n - name: 'jnkns'\n subresources:\n - name: 'projects'\n subresources:\n - name: 'jenkins'\n - name: 'jenkins2'\n - name: 'test'\n subresources:\n - name: 'projects'\n subresources:\n - name: 'test'\n\n # NEW Data WITH PREFIX\n - name: 'gen3'\n subresources:\n - name: 'programs'\n subresources:\n - name: 'QA'\n subresources:\n - name: 'projects'\n subresources:\n - name: 'test'\n - name: 'DEV'\n subresources:\n - name: 'projects'\n subresources:\n - name: 'test'\n - name: 'jnkns'\n subresources:\n - name: 'projects'\n subresources:\n - name: 'jenkins'\n - name: 'jenkins2'\n - name: 'test'\n subresources:\n - name: 'projects'\n subresources:\n - name: 'test'\n\n # consents obtained from DUO and NIH\n # https://github.com/EBISPOT/DUO\n # https://www.ncbi.nlm.nih.gov/pmc/articles/PMC4721915/\n - name: 'consents'\n subresources:\n - name: 'NRES'\n description: 'no restriction'\n - name: 'GRU'\n description: 'general research use'\n - name: 'GRU_CC'\n description: 'general research use and clinical care'\n - name: 'HMB'\n description: 'health/medical/biomedical research'\n - name: 'POA'\n description: 'population origins or ancestry research'\n - name: 'NMDS'\n description: 'no general methods research'\n - name: 'NPU'\n description: 'not-for-profit use only'\n - name: 'PUB'\n description: 'publication required'\n - name: 'DS_LungDisease'\n description: 'disease-specific research for lung disease'\n - name: 'DS_ChronicObstructivePulmonaryDisease'\n description: 'disease-specific research for chronic obstructive pulmonary disease'\n\n - name: 'abc'\n subresources:\n - name: 'programs'\n subresources:\n - name: 'foo'\n subresources:\n - name: 'projects'\n subresources:\n - name: 'bar'\n - name: 'test_program'\n subresources:\n - name: 'projects'\n subresources:\n - name: 'test_project1'\n - name: 'test_project2'\n - name: 'test_program2'\n subresources:\n - name: 'projects'\n subresources:\n - name: 'test_project3'\n\n\n # \"Sheepdog admin\" resources\n - name: 'services'\n subresources:\n - name: 'sheepdog'\n subresources:\n - name: 'submission'\n subresources:\n - name: 'program'\n - name: 'project'\n - name: 'indexd'\n subresources:\n - name: 'admin'\n - name: 'bundles'\n - name: audit\n subresources:\n - name: presigned_url\n - name: login\n\n\n - name: 'open'\n\n # action/methods:\n # create, read, update, delete, read-storage, write-storage,\n # file_upload, access\n roles:\n # General Access\n - id: 'file_uploader'\n description: 'can upload data files'\n permissions:\n - id: 'file_upload'\n action:\n service: '*'\n method: 'file_upload'\n - id: 'workspace_user'\n permissions:\n - id: 'workspace_access'\n action:\n service: 'jupyterhub'\n method: 'access'\n - id: 'dashboard_user'\n permissions:\n - id: 'dashboard_access'\n action:\n service: 'dashboard'\n method: 'access'\n - id: 'mds_user'\n permissions:\n - id: 'mds_access'\n action:\n service: 'mds_gateway'\n method: 'access'\n - id: 'prometheus_user'\n permissions:\n - id: 'prometheus_access'\n action:\n service: 'prometheus'\n method: 'access'\n - id: 'ttyadmin_user'\n permissions:\n - id: 'ttyadmin_access'\n action:\n service: 'ttyadmin'\n method: 'access'\n - id: 'sower_user'\n permissions:\n - id: 'sower_access'\n action:\n service: 'job'\n method: 'access'\n - id: 'mariner_admin'\n permissions:\n - id: 'mariner_access'\n action:\n service: 'mariner'\n method: 'access'\n - id: audit_reader\n permissions:\n - id: audit_reader_action\n action:\n service: audit\n method: read\n\n # All services\n - id: 'admin'\n description: ''\n permissions:\n - id: 'admin'\n action:\n service: '*'\n method: '*'\n - id: 'creator'\n description: ''\n permissions:\n - id: 'creator'\n action:\n service: '*'\n method: 'create'\n - id: 'reader'\n description: ''\n permissions:\n - id: 'reader'\n action:\n service: '*'\n method: 'read'\n - id: 'updater'\n description: ''\n permissions:\n - id: 'updater'\n action:\n service: '*'\n method: 'update'\n - id: 'deleter'\n description: ''\n permissions:\n - id: 'deleter'\n action:\n service: '*'\n method: 'delete'\n - id: 'storage_writer'\n description: ''\n permissions:\n - id: 'storage_writer'\n action:\n service: '*'\n method: 'write-storage'\n - id: 'storage_reader'\n description: ''\n permissions:\n - id: 'storage_reader'\n action:\n service: '*'\n method: 'read-storage'\n\n\n # Sheepdog admin role\n - id: 'sheepdog_admin'\n description: 'sheepdog admin role for program project crud'\n permissions:\n - id: 'sheepdog_admin_action'\n action:\n service: 'sheepdog'\n method: '*'\n\n\n # indexd\n - id: 'indexd_admin'\n # this only works if indexd.arborist is enabled in manifest!\n description: 'full access to indexd API'\n permissions:\n - id: 'indexd_admin'\n action:\n service: 'indexd'\n method: '*'\n - id: 'indexd_record_creator'\n description: ''\n permissions:\n - id: 'indexd_record_creator'\n action:\n service: 'indexd'\n method: 'create'\n - id: 'indexd_record_reader'\n description: ''\n permissions:\n - id: 'indexd_record_reader'\n action:\n service: 'indexd'\n method: 'read'\n - id: 'indexd_record_updater'\n description: ''\n permissions:\n - id: 'indexd_record_updater'\n action:\n service: 'indexd'\n method: 'update'\n - id: 'indexd_delete_record'\n description: ''\n permissions:\n - id: 'indexd_delete_record'\n action:\n service: 'indexd'\n method: 'delete'\n - id: 'indexd_storage_reader'\n description: ''\n permissions:\n - id: 'indexd_storage_reader'\n action:\n service: 'indexd'\n method: 'read-storage'\n - id: 'indexd_storage_writer'\n description: ''\n permissions:\n - id: 'indexd_storage_writer'\n action:\n service: 'indexd'\n method: 'write-storage'\n\n # arborist\n - id: 'arborist_creator'\n description: ''\n permissions:\n - id: 'arborist_creator'\n action:\n service: 'arborist'\n method: 'create'\n - id: 'arborist_reader'\n description: ''\n permissions:\n - id: 'arborist_reader'\n action:\n service: 'arborist'\n method: 'read'\n - id: 'arborist_updater'\n description: ''\n permissions:\n - id: 'arborist_updater'\n action:\n service: 'arborist'\n method: 'update'\n - id: 'arborist_deleter'\n description: ''\n permissions:\n - id: 'arborist_deleter'\n action:\n service: 'arborist'\n method: 'delete'\n\n # requestor\n - id: requestor_admin\n permissions:\n - id: requestor_admin_action\n action:\n service: requestor\n method: '*'\n - id: requestor_reader\n permissions:\n - id: requestor_reader_action\n action:\n service: requestor\n method: read\n - id: requestor_creator\n permissions:\n - id: requestor_creator_action\n action:\n service: requestor\n method: create\n - id: requestor_updater\n permissions:\n - id: requestor_updater_action\n action:\n service: requestor\n method: update\n - id: requestor_deleter\n permissions:\n - id: requestor_deleter_action\n action:\n service: requestor\n method: delete\n # argo\n - id: argo_user\n permissions:\n - id: argo_access\n action:\n service: argo\n method: access\n\nclients:\n basic-test-client:\n policies:\n - abc-admin\n - gen3-admin\n basic-test-abc-client:\n policies:\n - abc-admin\n wts:\n policies:\n - all_programs_reader\n - workspace\n\nusers:\n ### BEGIN INTERNS SECTION ###\n ### END INTERNS SECTION ###\n qureshi@uchicago.edu:\n admin: true\n policies:\n - data_upload\n - workspace\n - dashboard\n - mds_admin\n - prometheus\n - sower\n - services.sheepdog-admin\n - programs.QA-admin\n - programs.test-admin\n - programs.DEV-admin\n - programs.jnkns-admin\n - indexd_admin\n - ttyadmin\n projects:\n - auth_id: QA\n privilege: [create, read, update, delete, upload, read-storage]\n - auth_id: test\n privilege: [create, read, update, delete, upload, read-storage]\n - auth_id: DEV\n privilege: [create, read, update, delete, upload, read-storage]\n - auth_id: jenkins\n privilege: [create, read, update, delete, upload, read-storage]\n - auth_id: jenkins2\n privilege: [create, read, update, delete, upload, read-storage]\n - auth_id: jnkns\n privilege: [create, read, update, delete, upload, read-storage]\n"` | USER YAML. Passed in as a multiline string. | | affinity | map | `{"podAntiAffinity":{"preferredDuringSchedulingIgnoredDuringExecution":[{"podAffinityTerm":{"labelSelector":{"matchExpressions":[{"key":"app","operator":"In","values":["fence"]}]},"topologyKey":"kubernetes.io/hostname"},"weight":100}]}}` | Affinity to use for the deployment. | | affinity.podAntiAffinity.preferredDuringSchedulingIgnoredDuringExecution | map | `[{"podAffinityTerm":{"labelSelector":{"matchExpressions":[{"key":"app","operator":"In","values":["fence"]}]},"topologyKey":"kubernetes.io/hostname"},"weight":100}]` | Option for scheduling to be required or preferred. | @@ -88,14 +89,33 @@ A Helm chart for gen3 Fence | datadogLogsInjection | bool | `true` | If enabled, the Datadog Agent will automatically inject Datadog-specific metadata into your application logs. | | datadogProfilingEnabled | bool | `true` | If enabled, the Datadog Agent will collect profiling data for your application using the Continuous Profiler. This data can be used to identify performance bottlenecks and optimize your application. | | datadogTraceSampleRate | int | `1` | A value between 0 and 1, that represents the percentage of requests that will be traced. For example, a value of 0.5 means that 50% of requests will be traced. | -| env | list | `[{"name":"GEN3_UWSGI_TIMEOUT","valueFrom":{"configMapKeyRef":{"key":"uwsgi-timeout","name":"manifest-global","optional":true}}},{"name":"DD_AGENT_HOST","valueFrom":{"fieldRef":{"fieldPath":"status.hostIP"}}},{"name":"AWS_STS_REGIONAL_ENDPOINTS","value":"regional"},{"name":"PYTHONPATH","value":"/var/www/fence"},{"name":"GEN3_DEBUG","value":"False"},{"name":"FENCE_PUBLIC_CONFIG","valueFrom":{"configMapKeyRef":{"key":"fence-config-public.yaml","name":"manifest-fence","optional":true}}},{"name":"PGHOST","valueFrom":{"secretKeyRef":{"key":"host","name":"fence-dbcreds","optional":false}}},{"name":"PGUSER","valueFrom":{"secretKeyRef":{"key":"username","name":"fence-dbcreds","optional":false}}},{"name":"PGPASSWORD","valueFrom":{"secretKeyRef":{"key":"password","name":"fence-dbcreds","optional":false}}},{"name":"PGDB","valueFrom":{"secretKeyRef":{"key":"database","name":"fence-dbcreds","optional":false}}},{"name":"DBREADY","valueFrom":{"secretKeyRef":{"key":"dbcreated","name":"fence-dbcreds","optional":false}}},{"name":"DB","value":"postgresql://$(PGUSER):$(PGPASSWORD)@$(PGHOST):5432/$(PGDB)"},{"name":"INDEXD_PASSWORD","valueFrom":{"secretKeyRef":{"key":"fence","name":"indexd-service-creds"}}},{"name":"gen3Env","valueFrom":{"configMapKeyRef":{"key":"hostname","name":"manifest-global"}}}]` | Environment variables to pass to the container | +| env | list | `[{"name":"GEN3_UWSGI_TIMEOUT","valueFrom":{"configMapKeyRef":{"key":"uwsgi-timeout","name":"manifest-global","optional":true}}},{"name":"DD_AGENT_HOST","valueFrom":{"fieldRef":{"fieldPath":"status.hostIP"}}},{"name":"AWS_STS_REGIONAL_ENDPOINTS","value":"regional"},{"name":"PYTHONPATH","value":"/var/www/fence"},{"name":"GEN3_DEBUG","value":"False"},{"name":"PGHOST","valueFrom":{"secretKeyRef":{"key":"host","name":"fence-dbcreds","optional":false}}},{"name":"PGUSER","valueFrom":{"secretKeyRef":{"key":"username","name":"fence-dbcreds","optional":false}}},{"name":"PGPASSWORD","valueFrom":{"secretKeyRef":{"key":"password","name":"fence-dbcreds","optional":false}}},{"name":"PGDB","valueFrom":{"secretKeyRef":{"key":"database","name":"fence-dbcreds","optional":false}}},{"name":"DBREADY","valueFrom":{"secretKeyRef":{"key":"dbcreated","name":"fence-dbcreds","optional":false}}},{"name":"DB","value":"postgresql://$(PGUSER):$(PGPASSWORD)@$(PGHOST):5432/$(PGDB)"},{"name":"INDEXD_PASSWORD","valueFrom":{"secretKeyRef":{"key":"fence","name":"indexd-service-creds"}}},{"name":"gen3Env","valueFrom":{"configMapKeyRef":{"key":"hostname","name":"manifest-global"}}}]` | Environment variables to pass to the container | +| externalSecrets | map | `{"createK8sFenceConfigSecret":false,"createK8sGoogleAppSecrets":false,"createK8sJwtKeysSecret":false,"dbcreds":null,"fenceConfig":null,"fenceGoogleAppCredsSecret":null,"fenceGoogleStorageCredsSecret":null,"fenceJwtKeys":null}` | External Secrets settings. | +| externalSecrets.createK8sFenceConfigSecret | string | `false` | Will create the Helm "fence-config" secret even if Secrets Manager is enabled. This is helpful if you are wanting to use External Secrets for some, but not all secrets. | +| externalSecrets.createK8sGoogleAppSecrets | string | `false` | Will create the Helm "fence-google-app-creds-secret" and "fence-google-storage-creds-secret" secrets even if Secrets Manager is enabled. This is helpful if you are wanting to use External Secrets for some, but not all secrets. | +| externalSecrets.createK8sJwtKeysSecret | string | `false` | Will create the Helm "fence-jwt-keys" secret even if Secrets Manager is enabled. This is helpful if you are wanting to use External Secrets for some, but not all secrets. | +| externalSecrets.dbcreds | string | `nil` | Will override the name of the aws secrets manager secret. Default is "Values.global.environment-.Chart.Name-creds" | +| externalSecrets.fenceConfig | string | `nil` | Will override the name of the aws secrets manager secret. Default is "fence-config" | +| externalSecrets.fenceGoogleAppCredsSecret | string | `nil` | Will override the name of the aws secrets manager secret. Default is "fence-google-app-creds-secret" | +| externalSecrets.fenceGoogleStorageCredsSecret | string | `nil` | Will override the name of the aws secrets manager secret. Default is "fence-google-storage-creds-secret" | +| externalSecrets.fenceJwtKeys | string | `nil` | Will override the name of the aws secrets manager secret. Default is "fence-jwt-keys" | | fullnameOverride | string | `""` | Override the full name of the deployment. | -| global | map | `{"ddEnabled":false,"dev":true,"dictionaryUrl":"https://s3.amazonaws.com/dictionary-artifacts/datadictionary/develop/schema.json","dispatcherJobNum":10,"environment":"default","hostname":"localhost","kubeBucket":"kube-gen3","logsBucket":"logs-gen3","minAvialable":1,"netPolicy":true,"pdb":false,"portalApp":"gitops","postgres":{"dbCreate":true,"master":{"host":null,"password":null,"port":"5432","username":"postgres"}},"publicDataSets":true,"revproxyArn":"arn:aws:acm:us-east-1:123456:certificate","syncFromDbgap":false,"tierAccessLevel":"libre","tierAccessLimit":1000}` | Global configuration options. | +| global.aws | map | `{"awsAccessKeyId":null,"awsSecretAccessKey":null,"enabled":false,"useLocalSecret":{"enabled":false,"localSecretName":null,"localSecretNamespace":null}}` | AWS configuration | +| global.aws.awsAccessKeyId | string | `nil` | Credentials for AWS stuff. | +| global.aws.awsSecretAccessKey | string | `nil` | Credentials for AWS stuff. | +| global.aws.enabled | bool | `false` | Set to true if deploying to AWS. Controls ingress annotations. | +| global.aws.useLocalSecret | map | `{"enabled":false,"localSecretName":null,"localSecretNamespace":null}` | Local secret setting if using a pre-exising secret. | +| global.aws.useLocalSecret.enabled | bool | `false` | Set to true if you would like to use a secret that is already running on your cluster. | +| global.aws.useLocalSecret.localSecretName | string | `nil` | Name of the local secret. | +| global.aws.useLocalSecret.localSecretNamespace | string | `nil` | Namespace of the local secret. | | global.ddEnabled | bool | `false` | Whether Datadog is enabled. | | global.dev | bool | `true` | Whether the deployment is for development purposes. | | global.dictionaryUrl | string | `"https://s3.amazonaws.com/dictionary-artifacts/datadictionary/develop/schema.json"` | URL of the data dictionary. | -| global.dispatcherJobNum | int | `10` | Number of dispatcher jobs. | +| global.dispatcherJobNum | int | `"10"` | Number of dispatcher jobs. | | global.environment | string | `"default"` | Environment name. This should be the same as vpcname if you're doing an AWS deployment. Currently this is being used to share ALB's if you have multiple namespaces. Might be used other places too. | +| global.externalSecrets | map | `{"deploy":false,"separateSecretStore":false}` | External Secrets settings. | +| global.externalSecrets.deploy | bool | `false` | Will use ExternalSecret resources to pull secrets from Secrets Manager instead of creating them locally. Be cautious as this will override any fence secrets you have deployed. | +| global.externalSecrets.separateSecretStore | string | `false` | Will deploy a separate External Secret Store for this service. | | global.hostname | string | `"localhost"` | Hostname for the deployment. | | global.kubeBucket | string | `"kube-gen3"` | S3 bucket name for Kubernetes manifest files. | | global.logsBucket | string | `"logs-gen3"` | S3 bucket name for log files. | @@ -103,8 +123,8 @@ A Helm chart for gen3 Fence | global.netPolicy | bool | `true` | Whether network policies are enabled. | | global.pdb | bool | `false` | If the service will be deployed with a Pod Disruption Budget. Note- you need to have more than 2 replicas for the pdb to be deployed. | | global.portalApp | string | `"gitops"` | Portal application name. | -| global.postgres | map | `{"dbCreate":true,"master":{"host":null,"password":null,"port":"5432","username":"postgres"}}` | Postgres database configuration. | | global.postgres.dbCreate | bool | `true` | Whether the database should be created. | +| global.postgres.externalSecret | string | `""` | Name of external secret. Disabled if empty | | global.postgres.master | map | `{"host":null,"password":null,"port":"5432","username":"postgres"}` | Master credentials to postgres. This is going to be the default postgres server being used for each service, unless each service specifies their own postgres | | global.postgres.master.host | string | `nil` | hostname of postgres server | | global.postgres.master.password | string | `nil` | password for superuser in postgres. This is used to create or restore databases | @@ -114,13 +134,13 @@ A Helm chart for gen3 Fence | global.revproxyArn | string | `"arn:aws:acm:us-east-1:123456:certificate"` | ARN of the reverse proxy certificate. | | global.syncFromDbgap | bool | `false` | Whether to sync data from dbGaP. | | global.tierAccessLevel | string | `"libre"` | Access level for tiers. acceptable values for `tier_access_level` are: `libre`, `regular` and `private`. If omitted, by default common will be treated as `private` | -| global.tierAccessLimit | int | `1000` | Only relevant if tireAccessLevel is set to "regular". Summary charts below this limit will not appear for aggregated data. | -| image.pullPolicy | string | `"IfNotPresent"` | When to pull the image. This value should be "Always" to ensure the latest image is used. | +| global.tierAccessLimit | int | `"1000"` | Only relevant if tireAccessLevel is set to "regular". Summary charts below this limit will not appear for aggregated data. | +| image.pullPolicy | string | `"Always"` | When to pull the image. This value should be "Always" to ensure the latest image is used. | | image.repository | string | `"quay.io/cdis/fence"` | The Docker image repository for the fence service | | image.tag | string | `"master"` | Overrides the image tag whose default is the chart appVersion. | | imagePullSecrets | list | `[]` | Docker image pull secrets. | -| initEnv | list | `[{"name":"PGHOST","valueFrom":{"secretKeyRef":{"key":"host","name":"fence-dbcreds","optional":false}}},{"name":"PGUSER","valueFrom":{"secretKeyRef":{"key":"username","name":"fence-dbcreds","optional":false}}},{"name":"PGPASSWORD","valueFrom":{"secretKeyRef":{"key":"password","name":"fence-dbcreds","optional":false}}},{"name":"PGDB","valueFrom":{"secretKeyRef":{"key":"database","name":"fence-dbcreds","optional":false}}},{"name":"DBREADY","valueFrom":{"secretKeyRef":{"key":"dbcreated","name":"fence-dbcreds","optional":false}}},{"name":"DB","value":"postgresql://$(PGUSER):$(PGPASSWORD)@$(PGHOST):5432/$(PGDB)"},{"name":"FENCE_DB","value":"postgresql://$(PGUSER):$(PGPASSWORD)@$(PGHOST):5432/$(PGDB)"},{"name":"PYTHONPATH","value":"/var/www/fence"},{"name":"FENCE_PUBLIC_CONFIG","valueFrom":{"configMapKeyRef":{"key":"fence-config-public.yaml","name":"manifest-fence","optional":true}}}]` | Volumes to attach to the init container. | -| initVolumeMounts | list | `[{"mountPath":"/var/www/fence/fence-config.yaml","name":"config-volume","readOnly":true,"subPath":"fence-config.yaml"},{"mountPath":"/var/www/fence/yaml_merge.py","name":"yaml-merge","readOnly":true,"subPath":"yaml_merge.py"},{"mountPath":"/var/www/fence/fence_google_app_creds_secret.json","name":"fence-google-app-creds-secret-volume","readOnly":true,"subPath":"fence_google_app_creds_secret.json"},{"mountPath":"/var/www/fence/fence_google_storage_creds_secret.json","name":"fence-google-storage-creds-secret-volume","readOnly":true,"subPath":"fence_google_storage_creds_secret.json"}]` | Volumes to mount to the init container. | +| initEnv | list | `[{"name":"PGHOST","valueFrom":{"secretKeyRef":{"key":"host","name":"fence-dbcreds","optional":false}}},{"name":"PGUSER","valueFrom":{"secretKeyRef":{"key":"username","name":"fence-dbcreds","optional":false}}},{"name":"PGPASSWORD","valueFrom":{"secretKeyRef":{"key":"password","name":"fence-dbcreds","optional":false}}},{"name":"PGDB","valueFrom":{"secretKeyRef":{"key":"database","name":"fence-dbcreds","optional":false}}},{"name":"DBREADY","valueFrom":{"secretKeyRef":{"key":"dbcreated","name":"fence-dbcreds","optional":false}}},{"name":"DB","value":"postgresql://$(PGUSER):$(PGPASSWORD)@$(PGHOST):5432/$(PGDB)"},{"name":"FENCE_DB","value":"postgresql://$(PGUSER):$(PGPASSWORD)@$(PGHOST):5432/$(PGDB)"},{"name":"PYTHONPATH","value":"/var/www/fence"}]` | Volumes to attach to the init container. | +| initVolumeMounts | list | `[{"mountPath":"/var/www/fence/fence-config-secret.yaml","name":"config-volume","readOnly":true,"subPath":"fence-config.yaml"},{"mountPath":"/var/www/fence/fence-config-public.yaml","name":"config-volume-public","readOnly":true,"subPath":"fence-config-public.yaml"},{"mountPath":"/var/www/fence/yaml_merge.py","name":"yaml-merge","readOnly":true,"subPath":"yaml_merge.py"},{"mountPath":"/var/www/fence/fence_google_app_creds_secret.json","name":"fence-google-app-creds-secret-volume","readOnly":true,"subPath":"fence_google_app_creds_secret.json"},{"mountPath":"/var/www/fence/fence_google_storage_creds_secret.json","name":"fence-google-storage-creds-secret-volume","readOnly":true,"subPath":"fence_google_storage_creds_secret.json"}]` | Volumes to mount to the init container. | | labels | map | `{"authprovider":"yes","netnolimit":"yes","public":"yes","userhelper":"yes"}` | Labels to add to the pod. | | labels.authprovider | string | `"yes"` | Grants egress from all pods to pods labeled with authrpovider=yes. For network policy selectors. | | labels.netnolimit | string | `"yes"` | Grants egress from pods labeled with netnolimit=yes to any IP address. Use explicit proxy and AWS APIs | @@ -153,6 +173,9 @@ A Helm chart for gen3 Fence | resources.requests | map | `{"cpu":0.3,"memory":"128Mi"}` | The amount of resources that the container requests | | resources.requests.cpu | string | `0.3` | The amount of CPU requested | | resources.requests.memory | string | `"128Mi"` | The amount of memory requested | +| secrets | map | `{"awsAccessKeyId":null,"awsSecretAccessKey":null}` | Secret information for Usersync and External Secrets. | +| secrets.awsAccessKeyId | str | `nil` | AWS access key ID. Overrides global key. | +| secrets.awsSecretAccessKey | str | `nil` | AWS access key ID. Overrides global key. | | securityContext | map | `{}` | Security context for the containers in the pod | | selectorLabels | map | `nil` | Will completely override the selectorLabels defined in the common chart's _label_setup.tpl | | service | map | `{"port":80,"type":"ClusterIP"}` | Kubernetes service information. | @@ -168,21 +191,16 @@ A Helm chart for gen3 Fence | sidecar.pullPolicy | string | `"IfNotPresent"` | When to pull the image. | | sidecar.tag | string | `"nginx-sidecar-feat_nginx-sidecar"` | Image tag. | | tolerations | list | `[]` | Tolerations for the pods | -| usersync | map | `{"addDbgap":false,"custom_image":null,"onlyDbgap":false,"schedule":"*/30 * * * *","secrets":{"awsAccessKeyId":"","awsSecretAccessKey":""},"slack_send_dbgap":false,"slack_webhook":"None","syncFromDbgap":false,"userYamlS3Path":"s3://cdis-gen3-users/helm-test/user.yaml","usersync":false}` | Configuration options for usersync cronjob. | +| usersync | map | `{"addDbgap":false,"custom_image":null,"onlyDbgap":false,"schedule":"*/30 * * * *","slack_send_dbgap":false,"slack_webhook":"None","syncFromDbgap":false,"userYamlS3Path":"s3://cdis-gen3-users/helm-test/user.yaml","usersync":true}` | Configuration options for usersync cronjob. | | usersync.addDbgap | bool | `false` | Force attempting a dbgap sync if "true", falls back on user.yaml | | usersync.custom_image | string | `nil` | To set a custom image for pulling the user.yaml file from S3. Default is the Gen3 Awshelper image. | | usersync.onlyDbgap | bool | `false` | Forces ONLY a dbgap sync if "true", IGNORING user.yaml | | usersync.schedule | string | `"*/30 * * * *"` | The cron schedule expression to use in the usersync cronjob. Runs every 30 minutes by default. | -| usersync.secrets | map | `{"awsAccessKeyId":"","awsSecretAccessKey":""}` | Secret information | -| usersync.secrets.awsAccessKeyId | str | `""` | AWS access key ID for usersync S3 bucket | -| usersync.secrets.awsSecretAccessKey | str | `""` | AWS secret access key for usersync S3 bucket | | usersync.slack_send_dbgap | bool | `false` | Will echo what files we are seeing on dbgap ftp to Slack. | | usersync.slack_webhook | string | `"None"` | Slack webhook endpoint used with certain jobs. | | usersync.syncFromDbgap | bool | `false` | Whether to sync data from dbGaP. | | usersync.userYamlS3Path | string | `"s3://cdis-gen3-users/helm-test/user.yaml"` | Path to the user.yaml file in S3. | -| usersync.usersync | bool | `false` | Whether to run Fence usersync or not. | -| volumeMounts | list | `[{"mountPath":"/var/www/fence/local_settings.py","name":"old-config-volume","readOnly":true,"subPath":"local_settings.py"},{"mountPath":"/var/www/fence/fence_credentials.json","name":"json-secret-volume","readOnly":true,"subPath":"fence_credentials.json"},{"mountPath":"/var/www/fence/creds.json","name":"creds-volume","readOnly":true,"subPath":"creds.json"},{"mountPath":"/var/www/fence/config_helper.py","name":"config-helper","readOnly":true,"subPath":"config_helper.py"},{"mountPath":"/fence/fence/static/img/logo.svg","name":"logo-volume","readOnly":true,"subPath":"logo.svg"},{"mountPath":"/fence/fence/static/privacy_policy.md","name":"privacy-policy","readOnly":true,"subPath":"privacy_policy.md"},{"mountPath":"/var/www/fence/fence-config.yaml","name":"config-volume","readOnly":true,"subPath":"fence-config.yaml"},{"mountPath":"/var/www/fence/yaml_merge.py","name":"yaml-merge","readOnly":true,"subPath":"yaml_merge.py"},{"mountPath":"/var/www/fence/fence_google_app_creds_secret.json","name":"fence-google-app-creds-secret-volume","readOnly":true,"subPath":"fence_google_app_creds_secret.json"},{"mountPath":"/var/www/fence/fence_google_storage_creds_secret.json","name":"fence-google-storage-creds-secret-volume","readOnly":true,"subPath":"fence_google_storage_creds_secret.json"},{"mountPath":"/fence/keys/key/jwt_private_key.pem","name":"fence-jwt-keys","readOnly":false,"subPath":"jwt_private_key.pem"}]` | Volumes to mount to the container. | -| volumes | list | `[{"name":"old-config-volume","secret":{"secretName":"fence-secret"}},{"name":"json-secret-volume","secret":{"optional":true,"secretName":"fence-json-secret"}},{"name":"creds-volume","secret":{"secretName":"fence-creds"}},{"configMap":{"name":"config-helper","optional":true},"name":"config-helper"},{"configMap":{"name":"logo-config"},"name":"logo-volume"},{"name":"config-volume","secret":{"secretName":"fence-config"}},{"name":"fence-google-app-creds-secret-volume","secret":{"secretName":"fence-google-app-creds-secret"}},{"name":"fence-google-storage-creds-secret-volume","secret":{"secretName":"fence-google-storage-creds-secret"}},{"name":"fence-jwt-keys","secret":{"secretName":"fence-jwt-keys"}},{"configMap":{"name":"privacy-policy"},"name":"privacy-policy"},{"configMap":{"name":"fence-yaml-merge","optional":true},"name":"yaml-merge"},{"configMap":{"name":"fence-wsgi"},"name":"wsgi-config"},{"configMap":{"name":"fence-nginx-configmap"},"name":"nginx-config"}]` | Volumes to attach to the container. | +| usersync.usersync | bool | `true` | Whether to run Fence usersync or not. | +| volumeMounts | list | `[{"mountPath":"/var/www/fence/local_settings.py","name":"old-config-volume","readOnly":true,"subPath":"local_settings.py"},{"mountPath":"/var/www/fence/fence_credentials.json","name":"json-secret-volume","readOnly":true,"subPath":"fence_credentials.json"},{"mountPath":"/var/www/fence/creds.json","name":"creds-volume","readOnly":true,"subPath":"creds.json"},{"mountPath":"/var/www/fence/config_helper.py","name":"config-helper","readOnly":true,"subPath":"config_helper.py"},{"mountPath":"/fence/fence/static/img/logo.svg","name":"logo-volume","readOnly":true,"subPath":"logo.svg"},{"mountPath":"/fence/fence/static/privacy_policy.md","name":"privacy-policy","readOnly":true,"subPath":"privacy_policy.md"},{"mountPath":"/var/www/fence/fence-config-secret.yaml","name":"config-volume","readOnly":true,"subPath":"fence-config.yaml"},{"mountPath":"/var/www/fence/yaml_merge.py","name":"yaml-merge","readOnly":true,"subPath":"yaml_merge.py"},{"mountPath":"/var/www/fence/fence_google_app_creds_secret.json","name":"fence-google-app-creds-secret-volume","readOnly":true,"subPath":"fence_google_app_creds_secret.json"},{"mountPath":"/var/www/fence/fence_google_storage_creds_secret.json","name":"fence-google-storage-creds-secret-volume","readOnly":true,"subPath":"fence_google_storage_creds_secret.json"},{"mountPath":"/fence/keys/key/jwt_private_key.pem","name":"fence-jwt-keys","readOnly":true,"subPath":"jwt_private_key.pem"},{"mountPath":"/var/www/fence/fence-config-public.yaml","name":"config-volume-public","readOnly":true,"subPath":"fence-config-public.yaml"}]` | Volumes to mount to the container. | +| volumes | list | `[{"name":"old-config-volume","secret":{"secretName":"fence-secret"}},{"name":"json-secret-volume","secret":{"optional":true,"secretName":"fence-json-secret"}},{"name":"creds-volume","secret":{"secretName":"fence-creds"}},{"configMap":{"name":"config-helper","optional":true},"name":"config-helper"},{"configMap":{"name":"logo-config"},"name":"logo-volume"},{"name":"config-volume","secret":{"secretName":"fence-config"}},{"name":"fence-google-app-creds-secret-volume","secret":{"secretName":"fence-google-app-creds-secret"}},{"name":"fence-google-storage-creds-secret-volume","secret":{"secretName":"fence-google-storage-creds-secret"}},{"name":"fence-jwt-keys","secret":{"secretName":"fence-jwt-keys"}},{"configMap":{"name":"privacy-policy"},"name":"privacy-policy"},{"configMap":{"name":"fence-yaml-merge","optional":false},"name":"yaml-merge"},{"configMap":{"name":"manifest-fence","optional":true},"name":"config-volume-public"}]` | Volumes to attach to the container. | ----------------------------------------------- -Autogenerated from chart metadata using [helm-docs v1.11.0](https://github.com/norwoodj/helm-docs/releases/v1.11.0) diff --git a/helm/fence/scripts/yaml_merge.py b/helm/fence/scripts/yaml_merge.py new file mode 100644 index 00000000..5223f9f4 --- /dev/null +++ b/helm/fence/scripts/yaml_merge.py @@ -0,0 +1,56 @@ +import sys +import yaml + +''' +Helper script to merge arbitraly number of yaml files + +Usage: python yaml_merge.py file1.yaml file2.yaml ... fence-config.yaml + +Example: python yaml_merge.py file1.yaml file2.yaml fence-config.yaml +file1.yaml key(s) will overriden by items in file2.yaml if they exist, + +''' +def merge_yaml_files(file_paths): + merged_data = {} + + for file_path in file_paths: + try: + with open(file_path, 'r') as file: + data = yaml.safe_load(file) + merged_data = merge_dicts(merged_data, data) + except FileNotFoundError as e: + print('WARNING! File not found: {}. Will be ignored!'.format(file_path)) + + return merged_data + +def merge_dicts(dict1, dict2): + if dict2 is not None: #Fix AttributeError + for key, value in dict2.items(): + if key in dict1 and isinstance(dict1[key], dict) and isinstance(value, dict): + dict1[key] = merge_dicts(dict1[key], value) + else: + dict1[key] = value + + return dict1 + +def save_merged_file(merged_data, output_file_path): + with open(output_file_path, 'w') as output_file: + yaml.dump(merged_data, output_file, default_flow_style=False) + +if __name__ == "__main__": + # Check if at least two arguments are provided (including the script name) + if len(sys.argv) < 3: + print("Usage: python yaml_merge.py config-file1.yaml config-file2.yaml ... fence-config.yaml") + sys.exit(1) + + # Extract input file paths and output file path + input_files = sys.argv[1:-1] + output_file = sys.argv[-1] + + # Merge YAML files + merged_data = merge_yaml_files(input_files) + + # Save the merged data to the output file + save_merged_file(merged_data, output_file) + + print(f"Merged Configuration saved to {output_file}") diff --git a/helm/fence/templates/_helpers.tpl b/helm/fence/templates/_helpers.tpl index f7011103..c4a4aa77 100644 --- a/helm/fence/templates/_helpers.tpl +++ b/helm/fence/templates/_helpers.tpl @@ -95,4 +95,33 @@ Create the name of the service account to use {{- else }} {{- default .Values.postgres.password }} {{- end }} -{{- end }} \ No newline at end of file +{{- end }} + + +{{/* + Fence JWT Keys Secrets Manager Name +*/}} +{{- define "fence-jwt-keys" -}} +{{- default "fence-jwt-keys" .Values.externalSecrets.fenceJwtKeys }} +{{- end }} + +{{/* + Fence Google App Creds Secrets Manager Name +*/}} +{{- define "fence-google-app-creds-secret" -}} +{{- default "fence-google-app-creds-secret" .Values.externalSecrets.fenceGoogleAppCredsSecret }} +{{- end }} + +{{/* + Fence Google Storage Creds Secrets Manager Name +*/}} +{{- define "fence-google-storage-creds-secret" -}} +{{- default "fence-google-storage-creds-secret" .Values.externalSecrets.fenceGoogleStorageCredsSecret }} +{{- end }} + +{{/* + Fence Config Secrets Manager Name +*/}} +{{- define "fence-config" -}} +{{- default "fence-config" .Values.externalSecrets.fenceConfig }} +{{- end }} diff --git a/helm/fence/templates/aws-config.yaml b/helm/fence/templates/aws-config.yaml new file mode 100644 index 00000000..398770d3 --- /dev/null +++ b/helm/fence/templates/aws-config.yaml @@ -0,0 +1,3 @@ +{{- if or (.Values.secrets.awsSecretAccessKey) (.Values.global.aws.awsSecretAccessKey ) }} +{{ include "common.awsconfig" . }} +{{- end -}} \ No newline at end of file diff --git a/helm/fence/templates/aws-userysnc-creds.yaml b/helm/fence/templates/aws-userysnc-creds.yaml deleted file mode 100644 index c6baff53..00000000 --- a/helm/fence/templates/aws-userysnc-creds.yaml +++ /dev/null @@ -1,10 +0,0 @@ -apiVersion: v1 -kind: Secret -metadata: - name: aws-config-fence -type: Opaque -stringData: - credentials: | - [default] - aws_access_key_id={{.Values.usersync.secrets.awsAccessKeyId}} - aws_secret_access_key={{.Values.usersync.secrets.awsSecretAccessKey}} \ No newline at end of file diff --git a/helm/fence/templates/db-init.yaml b/helm/fence/templates/db-init.yaml index abbefb6e..5ef14e87 100644 --- a/helm/fence/templates/db-init.yaml +++ b/helm/fence/templates/db-init.yaml @@ -1,6 +1,6 @@ -{{ include "common.db_setup_job" . }} ---- {{ include "common.db-secret" . }} --- -{{ include "common.db_setup_sa" . }} +{{ include "common.db_setup_job" . }} --- +{{ include "common.db_setup_sa" . }} +--- \ No newline at end of file diff --git a/helm/fence/templates/external-secret.yaml b/helm/fence/templates/external-secret.yaml new file mode 100644 index 00000000..27e5ebc3 --- /dev/null +++ b/helm/fence/templates/external-secret.yaml @@ -0,0 +1,75 @@ +{{ if .Values.global.externalSecrets.deploy }} +apiVersion: external-secrets.io/v1beta1 +kind: ExternalSecret +metadata: + name: fence-jwt-keys +spec: + refreshInterval: 5m + secretStoreRef: + name: {{include "common.SecretStore" .}} + kind: SecretStore + target: + name: fence-jwt-keys + creationPolicy: Owner + data: + - secretKey: jwt_private_key.pem + remoteRef: + #name of secret in secrets manager + key: {{include "fence-jwt-keys" .}} +--- +apiVersion: external-secrets.io/v1beta1 +kind: ExternalSecret +metadata: + name: fence-google-app-creds-secret +spec: + refreshInterval: 5m + secretStoreRef: + name: {{include "common.SecretStore" .}} + kind: SecretStore + target: + name: fence-google-app-creds-secret + creationPolicy: Owner + data: + - secretKey: fence_google_app_creds_secret.json + remoteRef: + #name of secret in secrets manager + key: {{include "fence-google-app-creds-secret" .}} +--- +apiVersion: external-secrets.io/v1beta1 +kind: ExternalSecret +metadata: + name: fence-google-storage-creds-secret +spec: + refreshInterval: 5m + secretStoreRef: + name: {{include "common.SecretStore" .}} + kind: SecretStore + target: + name: fence-google-storage-creds-secret + creationPolicy: Owner + data: + - secretKey: fence_google_storage_creds_secret.json + remoteRef: + #name of secret in secrets manager + key: {{include "fence-google-storage-creds-secret" .}} +--- +apiVersion: external-secrets.io/v1beta1 +kind: ExternalSecret +metadata: + name: fence-config +spec: + refreshInterval: 5m + secretStoreRef: + name: {{include "common.SecretStore" .}} + kind: SecretStore + target: + name: fence-config + creationPolicy: Owner + data: + - secretKey: fence-config.yaml + remoteRef: + #name of secret in secrets manager + key: {{include "fence-config" .}} +{{- end }} +--- +{{ include "common.externalSecret.db" . }} \ No newline at end of file diff --git a/helm/fence/templates/fence-config-public.yaml b/helm/fence/templates/fence-config-public.yaml new file mode 100644 index 00000000..4e18796a --- /dev/null +++ b/helm/fence/templates/fence-config-public.yaml @@ -0,0 +1,10 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: manifest-fence +data: + fence-config-public.yaml: | + {{- with .Values.FENCE_CONFIG_PUBLIC }} + {{- toYaml . | nindent 4 }} + {{ end }} + diff --git a/helm/fence/templates/fence-config.yaml b/helm/fence/templates/fence-config.yaml index 29d0df2e..e594d072 100644 --- a/helm/fence/templates/fence-config.yaml +++ b/helm/fence/templates/fence-config.yaml @@ -1,3 +1,4 @@ +{{- if or (not .Values.global.externalSecrets.deploy) (and .Values.global.externalSecrets.deploy .Values.externalSecrets.createK8sFenceConfigSecret) }} apiVersion: v1 kind: Secret metadata: @@ -8,4 +9,5 @@ stringData: {{- with .Values.FENCE_CONFIG }} {{- toYaml . | nindent 4 }} {{ end }} ---- \ No newline at end of file +--- +{{- end }} diff --git a/helm/fence/templates/fence-deployment.yaml b/helm/fence/templates/fence-deployment.yaml index ee1ea2bb..809b5190 100644 --- a/helm/fence/templates/fence-deployment.yaml +++ b/helm/fence/templates/fence-deployment.yaml @@ -64,8 +64,10 @@ spec: args: - "-c" - | - # echo "${FENCE_PUBLIC_CONFIG:-""}" > "/var/www/fence/fence-config-public.yaml" - # python /var/www/fence/yaml_merge.py /var/www/fence/fence-config-public.yaml /var/www/fence/fence-config-secret.yaml > /var/www/fence/fence-config.yaml + python /var/www/fence/yaml_merge.py /var/www/fence/fence-config-public.yaml /var/www/fence/fence-config-secret.yaml /var/www/fence/fence-config.yaml + if [[ -f /fence/keys/key/jwt_private_key.pem ]]; then + openssl rsa -in /fence/keys/key/jwt_private_key.pem -pubout > /fence/keys/key/jwt_public_key.pem + fi bash /fence/dockerrun.bash && if [[ -f /dockerrun.sh ]]; then bash /dockerrun.sh; fi env: {{- if .Values.global.ddEnabled }} @@ -100,9 +102,7 @@ spec: args: - "-c" - | - # echo "${FENCE_PUBLIC_CONFIG:-""}" > "/var/www/fence/fence-config-public.yaml" - # python /var/www/fence/yaml_merge.py /var/www/fence/fence-config-public.yaml /var/www/fence/fence-config-secret.yaml > /var/www/fence/fence-config.yaml - # sleep infinity + python /var/www/fence/yaml_merge.py /var/www/fence/fence-config-public.yaml /var/www/fence/fence-config-secret.yaml /var/www/fence/fence-config.yaml if fence-create migrate --help > /dev/null 2>&1; then if ! grep -E 'ENABLE_DB_MIGRATION"?: *false' /var/www/fence/fence-config.yaml; then echo "Running db migration: fence-create migrate" @@ -129,4 +129,4 @@ spec: {{- with .Values.tolerations }} tolerations: {{- toYaml . | nindent 8 }} - {{- end }} + {{- end }} \ No newline at end of file diff --git a/helm/fence/templates/fence-secret.yaml b/helm/fence/templates/fence-secret.yaml index 6ac60bde..7bd3675a 100644 --- a/helm/fence/templates/fence-secret.yaml +++ b/helm/fence/templates/fence-secret.yaml @@ -5,6 +5,7 @@ metadata: type: Opaque data: {{ (.Files.Glob "fence-secret/*").AsSecrets | indent 2 }} +{{- if or (not .Values.global.externalSecrets.deploy) (and .Values.global.externalSecrets.deploy .Values.externalSecrets.createK8sGoogleAppSecrets) }} --- apiVersion: v1 kind: Secret @@ -21,3 +22,4 @@ metadata: type: Opaque data: {{ (.Files.Glob "fence-google-creds/*").AsSecrets | indent 2 }} +{{- end }} \ No newline at end of file diff --git a/helm/fence/templates/fence-yaml-merge.yaml b/helm/fence/templates/fence-yaml-merge.yaml new file mode 100644 index 00000000..4ec22b51 --- /dev/null +++ b/helm/fence/templates/fence-yaml-merge.yaml @@ -0,0 +1,6 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: fence-yaml-merge +data: +{{ (.Files.Glob "scripts/*").AsConfig | indent 2 }} \ No newline at end of file diff --git a/helm/fence/templates/jwt-keys.yaml b/helm/fence/templates/jwt-keys.yaml index 893a4488..06d10f28 100644 --- a/helm/fence/templates/jwt-keys.yaml +++ b/helm/fence/templates/jwt-keys.yaml @@ -1,3 +1,4 @@ +{{- if or (not .Values.global.externalSecrets.deploy) (and .Values.global.externalSecrets.deploy .Values.externalSecrets.createK8sJwtKeysSecret) }} apiVersion: v1 kind: Secret metadata: @@ -5,3 +6,4 @@ metadata: type: Opaque data: jwt_private_key.pem: {{ include "getOrCreatePrivateKey" . }} +{{- end }} \ No newline at end of file diff --git a/helm/fence/templates/presigned-url-fence.yaml b/helm/fence/templates/presigned-url-fence.yaml index f007cdda..72cce99a 100644 --- a/helm/fence/templates/presigned-url-fence.yaml +++ b/helm/fence/templates/presigned-url-fence.yaml @@ -58,8 +58,7 @@ spec: args: - "-c" - | - echo "${FENCE_PUBLIC_CONFIG:-""}" > "/var/www/fence/fence-config-public.yaml" - python /var/www/fence/yaml_merge.py /var/www/fence/fence-config-public.yaml /var/www/fence/fence-config-secret.yaml > /var/www/fence/fence-config.yaml + python /var/www/fence/yaml_merge.py /var/www/fence/fence-config-public.yaml /var/www/fence/fence-config-secret.yaml /var/www/fence/fence-config.yaml if [[ -f /fence/keys/key/jwt_private_key.pem ]]; then openssl rsa -in /fence/keys/key/jwt_private_key.pem -pubout > /fence/keys/key/jwt_public_key.pem fi diff --git a/helm/fence/templates/secret-store.yaml b/helm/fence/templates/secret-store.yaml new file mode 100644 index 00000000..771c7760 --- /dev/null +++ b/helm/fence/templates/secret-store.yaml @@ -0,0 +1,3 @@ +{{ if .Values.global.externalSecrets.separateSecretStore }} +{{ include "common.secretstore" . }} +{{- end }} \ No newline at end of file diff --git a/helm/fence/templates/usersync-cron.yaml b/helm/fence/templates/usersync-cron.yaml index ef683944..7bf9d8b8 100644 --- a/helm/fence/templates/usersync-cron.yaml +++ b/helm/fence/templates/usersync-cron.yaml @@ -52,12 +52,75 @@ spec: emptyDir: {} - name: cred-volume secret: - secretName: aws-config-fence + {{- if .Values.global.aws.useLocalSecret.enabled }} + secretName: {{ .Values.global.aws.useLocalSecret.localSecretName }} + {{- else }} + secretName: {{.Chart.Name}}-aws-config + {{- end }} initContainers: - name: wait-for-fence image: curlimages/curl:latest command: ["/bin/sh","-c"] args: ["while [ $(curl -sw '%{http_code}' http://fence-service -o /dev/null) -ne 200 ]; do sleep 5; echo 'Waiting for fence...'; done"] + - name: awshelper + image: {{ .Values.usersync.custom_image | default "quay.io/cdis/awshelper:master" }} + imagePullPolicy: Always + env: + - name: gen3Env + valueFrom: + configMapKeyRef: + name: manifest-global + key: hostname + - name: userYamlS3Path + value: {{ .Values.usersync.userYamlS3Path | quote }} + - name: slackWebHook + value: {{ .Values.usersync.slack_webhook | quote }} + volumeMounts: + - name: user-yaml + mountPath: /var/www/fence + - name: shared-data + mountPath: /mnt/shared + - name: cred-volume + mountPath: "/home/ubuntu/.aws/credentials" + subPath: credentials + command: ["/bin/bash" ] + args: + - "-c" + - | + GEN3_HOME=/home/ubuntu/cloud-automation + source "${GEN3_HOME}/gen3/lib/utils.sh" + gen3_load "gen3/gen3setup" + + if [ "${userYamlS3Path}" = 'none' ]; then + echo "using local user.yaml" + cp /var/www/fence/user.yaml /mnt/shared/user.yaml + else + # ----------------- + echo "awshelper downloading ${userYamlS3Path} to /mnt/shared/user.yaml" + n=0 + until [ $n -ge 5 ]; do + echo "Download attempt $n" + aws s3 cp "${userYamlS3Path}" /mnt/shared/user.yaml && break + n=$[$n+1] + sleep 2 + done + fi + if [[ ! -f /mnt/shared/user.yaml ]]; then + echo "awshelper failed to retrieve /mnt/shared/user.yaml" + exit 1 + fi + #----------- + echo "awshelper updating etl configmap" + if ! gen3 gitops etl-convert < /mnt/shared/user.yaml > /tmp/user.yaml; then + echo "ERROR: failed to generate ETL config" + exit 1 + fi + # kubectl delete configmap fence > /dev/null 2>&1 + # kubectl create configmap fence --from-file=/tmp/user.yaml + if [ "${slackWebHook}" != 'None' ]; then + curl -X POST --data-urlencode "payload={\"text\": \"AWSHelper: Syncing users on ${gen3Env}\"}" "${slackWebHook}" + fi + echo "Helper exit ok" containers: - name: usersync image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" @@ -102,7 +165,7 @@ spec: # Script always succeeds if it runs (echo exits with 0) - | echo 'options use-vc' >> /etc/resolv.conf - pip3 install SQLAlchemy==1.3.6 + # pip3 install SQLAlchemy==1.3.6 # can be removed once this is merged: https://github.com/uc-cdis/fence/pull/1096 if [[ "$SYNC_FROM_DBGAP" != "true" && "$ADD_DBGAP" != "true" ]]; then if [[ -f /mnt/shared/user.yaml ]]; then @@ -147,65 +210,5 @@ spec: fi echo "Exit code: $exitcode" exit "$exitcode" - - name: awshelper - image: {{ .Values.usersync.custom_image | default "quay.io/cdis/awshelper:master" }} - imagePullPolicy: Always - env: - - name: gen3Env - valueFrom: - configMapKeyRef: - name: manifest-global - key: hostname - - name: userYamlS3Path - value: {{ .Values.usersync.userYamlS3Path | quote }} - - name: slackWebHook - value: {{ .Values.usersync.slack_webhook | quote }} - volumeMounts: - - name: user-yaml - mountPath: /var/www/fence - - name: shared-data - mountPath: /mnt/shared - - name: cred-volume - mountPath: "/home/ubuntu/.aws/credentials" - subPath: credentials - command: ["/bin/bash" ] - args: - - "-c" - - | - GEN3_HOME=/home/ubuntu/cloud-automation - source "${GEN3_HOME}/gen3/lib/utils.sh" - gen3_load "gen3/gen3setup" - - if [ "${userYamlS3Path}" = 'none' ]; then - echo "using local user.yaml" - cp /var/www/fence/user.yaml /mnt/shared/user.yaml - else - # ----------------- - echo "awshelper downloading ${userYamlS3Path} to /mnt/shared/user.yaml" - n=0 - until [ $n -ge 5 ]; do - echo "Download attempt $n" - aws s3 cp "${userYamlS3Path}" /mnt/shared/user.yaml && break - n=$[$n+1] - sleep 2 - echo "test 1" - done - fi - if [[ ! -f /mnt/shared/user.yaml ]]; then - echo "awshelper failed to retrieve /mnt/shared/user.yaml" - exit 1 - fi - #----------- - echo "awshelper updating etl configmap" - if ! gen3 gitops etl-convert < /mnt/shared/user.yaml > /tmp/user.yaml; then - echo "ERROR: failed to generate ETL config" - exit 1 - fi - # kubectl delete configmap fence > /dev/null 2>&1 - # kubectl create configmap fence --from-file=/tmp/user.yaml - if [ "${slackWebHook}" != 'None' ]; then - curl -X POST --data-urlencode "payload={\"text\": \"AWSHelper: Syncing users on ${gen3Env}\"}" "${slackWebHook}" - fi - echo "Helper exit ok" restartPolicy: "Never" {{- end }} \ No newline at end of file diff --git a/helm/fence/templates/usersync-sa.yaml b/helm/fence/templates/usersync-sa.yaml index 379271ce..f86ff821 100644 --- a/helm/fence/templates/usersync-sa.yaml +++ b/helm/fence/templates/usersync-sa.yaml @@ -5,7 +5,7 @@ metadata: name: usersync-job --- apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole +kind: Role metadata: name: usersync-job-role rules: @@ -14,12 +14,12 @@ rules: verbs: ["get", "list", "watch", "create", "update", "delete"] --- apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding +kind: RoleBinding metadata: name: usersync-job-role-binding roleRef: apiGroup: rbac.authorization.k8s.io - kind: ClusterRole + kind: Role name: usersync-job-role subjects: - kind: ServiceAccount diff --git a/helm/fence/values.yaml b/helm/fence/values.yaml index 0ea4cd01..777508b5 100644 --- a/helm/fence/values.yaml +++ b/helm/fence/values.yaml @@ -2,14 +2,33 @@ # This is a YAML-formatted file. # Declare variables to be passed into your templates. -# -- (map) Global configuration options. + +# Global configuration global: + # -- (map) AWS configuration + aws: + # -- (bool) Set to true if deploying to AWS. Controls ingress annotations. + enabled: false + # -- (string) Credentials for AWS stuff. + awsAccessKeyId: + # -- (string) Credentials for AWS stuff. + awsSecretAccessKey: + # -- (map) Local secret setting if using a pre-exising secret. + useLocalSecret: + # -- (bool) Set to true if you would like to use a secret that is already running on your cluster. + enabled: false + # -- (string) Name of the local secret. + localSecretName: + # -- (string) Namespace of the local secret. + localSecretNamespace: # -- (bool) Whether the deployment is for development purposes. dev: true - # -- (map) Postgres database configuration. + postgres: # -- (bool) Whether the database should be created. dbCreate: true + # -- (string) Name of external secret. Disabled if empty + externalSecret: "" # -- (map) Master credentials to postgres. This is going to be the default postgres server being used for each service, unless each service specifies their own postgres master: # -- (string) hostname of postgres server @@ -41,17 +60,70 @@ global: # -- (string) Access level for tiers. acceptable values for `tier_access_level` are: `libre`, `regular` and `private`. If omitted, by default common will be treated as `private` tierAccessLevel: libre # -- (int) Only relevant if tireAccessLevel is set to "regular". Summary charts below this limit will not appear for aggregated data. - tierAccessLimit: 1000 + tierAccessLimit: "1000" # -- (bool) Whether network policies are enabled. netPolicy: true # -- (int) Number of dispatcher jobs. - dispatcherJobNum: 10 + dispatcherJobNum: "10" # -- (bool) Whether Datadog is enabled. ddEnabled: false # -- (bool) If the service will be deployed with a Pod Disruption Budget. Note- you need to have more than 2 replicas for the pdb to be deployed. pdb: false # -- (int) The minimum amount of pods that are available at all times if the PDB is deployed. minAvialable: 1 + # -- (map) External Secrets settings. + externalSecrets: + # -- (bool) Will use ExternalSecret resources to pull secrets from Secrets Manager instead of creating them locally. Be cautious as this will override any fence secrets you have deployed. + deploy: false + # -- (string) Will deploy a separate External Secret Store for this service. + separateSecretStore: false + +# -- (map) External Secrets settings. +externalSecrets: + # -- (string) Will create the Helm "fence-config" secret even if Secrets Manager is enabled. This is helpful if you are wanting to use External Secrets for some, but not all secrets. + createK8sFenceConfigSecret: false + # -- (string) Will create the Helm "fence-jwt-keys" secret even if Secrets Manager is enabled. This is helpful if you are wanting to use External Secrets for some, but not all secrets. + createK8sJwtKeysSecret: false + # -- (string) Will create the Helm "fence-google-app-creds-secret" and "fence-google-storage-creds-secret" secrets even if Secrets Manager is enabled. This is helpful if you are wanting to use External Secrets for some, but not all secrets. + createK8sGoogleAppSecrets: false + # -- (string) Will override the name of the aws secrets manager secret. Default is "fence-jwt-keys" + fenceJwtKeys: + # -- (string) Will override the name of the aws secrets manager secret. Default is "fence-google-app-creds-secret" + fenceGoogleAppCredsSecret: + # -- (string) Will override the name of the aws secrets manager secret. Default is "fence-google-storage-creds-secret" + fenceGoogleStorageCredsSecret: + # -- (string) Will override the name of the aws secrets manager secret. Default is "fence-config" + fenceConfig: + # -- (string) Will override the name of the aws secrets manager secret. Default is "Values.global.environment-.Chart.Name-creds" + dbcreds: + +# -- (map) Configuration options for usersync cronjob. +usersync: + # -- (bool) Whether to run Fence usersync or not. + usersync: true + # -- (string) The cron schedule expression to use in the usersync cronjob. Runs every 30 minutes by default. + schedule: "*/30 * * * *" + # -- (string) To set a custom image for pulling the user.yaml file from S3. Default is the Gen3 Awshelper image. + custom_image: + # -- (bool) Whether to sync data from dbGaP. + syncFromDbgap: false + # -- (bool) Force attempting a dbgap sync if "true", falls back on user.yaml + addDbgap: false + # -- (bool) Forces ONLY a dbgap sync if "true", IGNORING user.yaml + onlyDbgap: false + # -- (string) Path to the user.yaml file in S3. + userYamlS3Path: s3://cdis-gen3-users/helm-test/user.yaml + # -- (string) Slack webhook endpoint used with certain jobs. + slack_webhook: None + # -- (bool) Will echo what files we are seeing on dbgap ftp to Slack. + slack_send_dbgap: false + +# -- (map) Secret information for Usersync and External Secrets. +secrets: + # -- (str) AWS access key ID. Overrides global key. + awsAccessKeyId: + # -- (str) AWS access key ID. Overrides global key. + awsSecretAccessKey: # -- (map) Postgres database configuration. If db does not exist in postgres cluster and dbCreate is set ot true then these databases will be created for you postgres: @@ -80,33 +152,6 @@ postgresql: # -- (bool) Option to persist the dbs data. enabled: false -# -- (map) Configuration options for usersync cronjob. -usersync: - # -- (bool) Whether to run Fence usersync or not. - usersync: false - # -- (map) Secret information - secrets: - # -- (str) AWS access key ID for usersync S3 bucket - awsAccessKeyId: "" - # -- (str) AWS secret access key for usersync S3 bucket - awsSecretAccessKey: "" - # -- (string) The cron schedule expression to use in the usersync cronjob. Runs every 30 minutes by default. - schedule: "*/30 * * * *" - # -- (string) To set a custom image for pulling the user.yaml file from S3. Default is the Gen3 Awshelper image. - custom_image: - # -- (bool) Whether to sync data from dbGaP. - syncFromDbgap: false - # -- (bool) Force attempting a dbgap sync if "true", falls back on user.yaml - addDbgap: false - # -- (bool) Forces ONLY a dbgap sync if "true", IGNORING user.yaml - onlyDbgap: false - # -- (string) Path to the user.yaml file in S3. - userYamlS3Path: s3://cdis-gen3-users/helm-test/user.yaml - # -- (string) Slack webhook endpoint used with certain jobs. - slack_webhook: None - # -- (bool) Will echo what files we are seeing on dbgap ftp to Slack. - slack_send_dbgap: false - # -- (int) Number of desired replicas replicaCount: 1 @@ -256,12 +301,6 @@ env: value: /var/www/fence - name: GEN3_DEBUG value: "False" - - name: FENCE_PUBLIC_CONFIG - valueFrom: - configMapKeyRef: - name: manifest-fence - key: fence-config-public.yaml - optional: true - name: PGHOST valueFrom: secretKeyRef: @@ -342,6 +381,10 @@ volumes: - name: yaml-merge configMap: name: "fence-yaml-merge" + optional: false + - name: config-volume-public + configMap: + name: "manifest-fence" optional: true - name: wsgi-config configMap: @@ -378,7 +421,7 @@ volumeMounts: subPath: "privacy_policy.md" - name: "config-volume" readOnly: true - mountPath: "/var/www/fence/fence-config.yaml" + mountPath: "/var/www/fence/fence-config-secret.yaml" subPath: fence-config.yaml - name: "yaml-merge" readOnly: true @@ -396,13 +439,21 @@ volumeMounts: readOnly: false mountPath: "/fence/keys/key/jwt_private_key.pem" subPath: "jwt_private_key.pem" + - name: "config-volume-public" + readOnly: true + mountPath: "/var/www/fence/fence-config-public.yaml" + subPath: fence-config-public.yaml # -- (list) Volumes to mount to the init container. initVolumeMounts: - name: "config-volume" readOnly: true - mountPath: "/var/www/fence/fence-config.yaml" + mountPath: "/var/www/fence/fence-config-secret.yaml" subPath: fence-config.yaml + - name: "config-volume-public" + readOnly: true + mountPath: "/var/www/fence/fence-config-public.yaml" + subPath: fence-config-public.yaml - name: "yaml-merge" readOnly: true mountPath: "/var/www/fence/yaml_merge.py" @@ -454,12 +505,6 @@ initEnv: value: postgresql://$(PGUSER):$(PGPASSWORD)@$(PGHOST):5432/$(PGDB) - name: PYTHONPATH value: /var/www/fence - - name: FENCE_PUBLIC_CONFIG - valueFrom: - configMapKeyRef: - name: manifest-fence - key: fence-config-public.yaml - optional: true # Values to determine the labels that are used for the deployment, pod, etc. # -- (string) Valid options are "production" or "dev". If invalid option is set- the value will default to "dev". @@ -1364,8 +1409,10 @@ USER_YAML: | - auth_id: jnkns privilege: [create, read, update, delete, upload, read-storage] +# -- (map) Public configuration settings for Fence app +FENCE_CONFIG_PUBLIC: {} -# -- (map) Configuration settings for Fence app +# -- (map) Private configuration settings for Fence app FENCE_CONFIG: # -- (string) Name of the Fence app APP_NAME: 'Gen3 Data Commons' diff --git a/helm/frontend-framework/Chart.yaml b/helm/frontend-framework/Chart.yaml new file mode 100644 index 00000000..a86f9eb1 --- /dev/null +++ b/helm/frontend-framework/Chart.yaml @@ -0,0 +1,29 @@ +apiVersion: v2 +name: frontend-framework +description: A Helm chart for the gen3 frontend framework + +# A chart can be either an 'application' or a 'library' chart. +# +# Application charts are a collection of templates that can be packaged into versioned archives +# to be deployed. +# +# Library charts provide useful utilities or functions for the chart developer. They're included as +# a dependency of application charts to inject those utilities and functions into the rendering +# pipeline. Library charts do not define any templates and, therefore, cannot be deployed. +type: application + +# This is the chart version. This version number should be incremented each time you make changes +# to the chart and its templates, including the app version. +# Versions are expected to follow Semantic Versioning (https://semver.org/) +version: 0.1.1 + +# This is the version number of the application being deployed. This version number should be +# incremented each time you make changes to the application. Versions are not expected to +# follow Semantic Versioning. They should reflect the version the application is using. +# It is recommended to use it with quotes. +appVersion: "develop" + +dependencies: +- name: common + version: 0.1.10 + repository: file://../common diff --git a/helm/frontend-framework/README.md b/helm/frontend-framework/README.md new file mode 100644 index 00000000..8c515bb3 --- /dev/null +++ b/helm/frontend-framework/README.md @@ -0,0 +1,95 @@ +# frontend-framework + +![Version: 0.1.1](https://img.shields.io/badge/Version-0.1.1-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: develop](https://img.shields.io/badge/AppVersion-develop-informational?style=flat-square) + +A Helm chart for the gen3 frontend framework + +## Requirements + +| Repository | Name | Version | +|------------|------|---------| +| file://../common | common | 0.1.10 | + +## Values + +| Key | Type | Default | Description | +|-----|------|---------|-------------| +| affinity | map | `{"podAntiAffinity":{"preferredDuringSchedulingIgnoredDuringExecution":[{"podAffinityTerm":{"labelSelector":{"matchExpressions":[{"key":"app","operator":"In","values":["frontend-framework"]}]},"topologyKey":"kubernetes.io/hostname"},"weight":100}]}}` | Affinity to use for the deployment. | +| affinity.podAntiAffinity.preferredDuringSchedulingIgnoredDuringExecution | map | `[{"podAffinityTerm":{"labelSelector":{"matchExpressions":[{"key":"app","operator":"In","values":["frontend-framework"]}]},"topologyKey":"kubernetes.io/hostname"},"weight":100}]` | Option for scheduling to be required or preferred. | +| affinity.podAntiAffinity.preferredDuringSchedulingIgnoredDuringExecution[0] | int | `{"podAffinityTerm":{"labelSelector":{"matchExpressions":[{"key":"app","operator":"In","values":["frontend-framework"]}]},"topologyKey":"kubernetes.io/hostname"},"weight":100}` | Weight value for preferred scheduling. | +| affinity.podAntiAffinity.preferredDuringSchedulingIgnoredDuringExecution[0].podAffinityTerm.labelSelector.matchExpressions[0] | list | `{"key":"app","operator":"In","values":["frontend-framework"]}` | Label key for match expression. | +| affinity.podAntiAffinity.preferredDuringSchedulingIgnoredDuringExecution[0].podAffinityTerm.labelSelector.matchExpressions[0].operator | string | `"In"` | Operation type for the match expression. | +| affinity.podAntiAffinity.preferredDuringSchedulingIgnoredDuringExecution[0].podAffinityTerm.labelSelector.matchExpressions[0].values | list | `["frontend-framework"]` | Value for the match expression key. | +| affinity.podAntiAffinity.preferredDuringSchedulingIgnoredDuringExecution[0].podAffinityTerm.topologyKey | string | `"kubernetes.io/hostname"` | Value for topology key label. | +| automountServiceAccountToken | bool | `false` | Automount the default service account token | +| autoscaling | map | `{"enabled":false,"maxReplicas":100,"minReplicas":1,"targetCPUUtilizationPercentage":80}` | Configuration for autoscaling the number of replicas | +| autoscaling.enabled | bool | `false` | Whether autoscaling is enabled | +| autoscaling.maxReplicas | int | `100` | The maximum number of replicas to scale up to | +| autoscaling.minReplicas | int | `1` | The minimum number of replicas to scale down to | +| autoscaling.targetCPUUtilizationPercentage | int | `80` | The target CPU utilization percentage for autoscaling | +| commonLabels | map | `nil` | Will completely override the commonLabels defined in the common chart's _label_setup.tpl | +| criticalService | string | `"true"` | Valid options are "true" or "false". If invalid option is set- the value will default to "false". | +| datadogLogsInjection | bool | `false` | If enabled, the Datadog Agent will automatically inject Datadog-specific metadata into your application logs. | +| datadogProfilingEnabled | bool | `false` | If enabled, the Datadog Agent will collect profiling data for your application using the Continuous Profiler. This data can be used to identify performance bottlenecks and optimize your application. | +| datadogTraceSampleRate | int | `1` | A value between 0 and 1, that represents the percentage of requests that will be traced. For example, a value of 0.5 means that 50% of requests will be traced. | +| fullnameOverride | string | `""` | Override the full name of the deployment. | +| global | map | `{"aws":{"awsAccessKeyId":null,"awsSecretAccessKey":null,"enabled":false},"ddEnabled":false,"dev":true,"dictionaryUrl":"https://s3.amazonaws.com/dictionary-artifacts/datadictionary/develop/schema.json","dispatcherJobNum":10,"environment":"default","hostname":"localhost","kubeBucket":"kube-gen3","logsBucket":"logs-gen3","netPolicy":true,"portalApp":"gitops","postgres":{"dbCreate":true,"master":{"host":null,"password":null,"port":"5432","username":"postgres"}},"publicDataSets":true,"revproxyArn":"arn:aws:acm:us-east-1:123456:certificate","syncFromDbgap":false,"tierAccessLevel":"libre","userYamlS3Path":"s3://cdis-gen3-users/test/user.yaml"}` | Global configuration options. | +| global.aws | map | `{"awsAccessKeyId":null,"awsSecretAccessKey":null,"enabled":false}` | AWS configuration | +| global.aws.awsAccessKeyId | string | `nil` | Credentials for AWS stuff. | +| global.aws.awsSecretAccessKey | string | `nil` | Credentials for AWS stuff. | +| global.aws.enabled | bool | `false` | Set to true if deploying to AWS. Controls ingress annotations. | +| global.ddEnabled | bool | `false` | Whether Datadog is enabled. | +| global.dev | bool | `true` | Whether the deployment is for development purposes. | +| global.dictionaryUrl | string | `"https://s3.amazonaws.com/dictionary-artifacts/datadictionary/develop/schema.json"` | URL of the data dictionary. | +| global.dispatcherJobNum | int | `10` | Number of dispatcher jobs. | +| global.environment | string | `"default"` | Environment name. This should be the same as vpcname if you're doing an AWS deployment. Currently this is being used to share ALB's if you have multiple namespaces. Might be used other places too. | +| global.hostname | string | `"localhost"` | Hostname for the deployment. | +| global.kubeBucket | string | `"kube-gen3"` | S3 bucket name for Kubernetes manifest files. | +| global.logsBucket | string | `"logs-gen3"` | S3 bucket name for log files. | +| global.netPolicy | bool | `true` | Whether network policies are enabled. | +| global.portalApp | string | `"gitops"` | Portal application name. | +| global.postgres | map | `{"dbCreate":true,"master":{"host":null,"password":null,"port":"5432","username":"postgres"}}` | Postgres database configuration. | +| global.postgres.dbCreate | bool | `true` | Whether the database should be created. | +| global.postgres.master | map | `{"host":null,"password":null,"port":"5432","username":"postgres"}` | Master credentials to postgres. This is going to be the default postgres server being used for each service, unless each service specifies their own postgres | +| global.postgres.master.host | string | `nil` | hostname of postgres server | +| global.postgres.master.password | string | `nil` | password for superuser in postgres. This is used to create or restore databases | +| global.postgres.master.port | string | `"5432"` | Port for Postgres. | +| global.postgres.master.username | string | `"postgres"` | username of superuser in postgres. This is used to create or restore databases | +| global.publicDataSets | bool | `true` | Whether public datasets are enabled. | +| global.revproxyArn | string | `"arn:aws:acm:us-east-1:123456:certificate"` | ARN of the reverse proxy certificate. | +| global.syncFromDbgap | bool | `false` | Whether to sync data from dbGaP. | +| global.tierAccessLevel | string | `"libre"` | Access level for tiers. acceptable values for `tier_access_level` are: `libre`, `regular` and `private`. If omitted, by default common will be treated as `private`. | +| global.userYamlS3Path | string | `"s3://cdis-gen3-users/test/user.yaml"` | Path to the user.yaml file in S3. | +| image | map | `{"pullPolicy":"Always","repository":"quay.io/cdis/frontend-framework","tag":"develop"}` | Docker image information. | +| image.pullPolicy | string | `"Always"` | Docker pull policy. | +| image.repository | string | `"quay.io/cdis/frontend-framework"` | Docker repository. | +| image.tag | string | `"develop"` | Overrides the image tag whose default is the chart appVersion. | +| imagePullSecrets | list | `[]` | Docker image pull secrets. | +| nameOverride | string | `""` | Override the name of the chart. | +| nodeSelector | map | `{}` | Node selector to apply to the pod | +| partOf | string | `"Front-End"` | Label to help organize pods and their use. Any value is valid, but use "_" or "-" to divide words. | +| podAnnotations | map | `{}` | Annotations to add to the pod | +| podSecurityContext | map | `{}` | Security context to apply to the pod | +| release | string | `"dev"` | Valid options are "production" or "dev". If invalid option is set- the value will default to "dev". | +| replicaCount | int | `1` | Number of replicas for the deployment. | +| resources | map | `{"limits":{"cpu":0.6,"memory":"4096Mi"},"requests":{"cpu":0.6,"memory":"512Mi"}}` | Resource requests and limits for the containers in the pod | +| resources.limits | map | `{"cpu":0.6,"memory":"4096Mi"}` | The maximum amount of resources that the container is allowed to use | +| resources.limits.cpu | string | `0.6` | The maximum amount of memory the container can use | +| resources.requests | map | `{"cpu":0.6,"memory":"512Mi"}` | The amount of resources that the container requests | +| resources.requests.cpu | string | `0.6` | The amount of CPU requested | +| resources.requests.memory | string | `"512Mi"` | The amount of memory requested | +| revisionHistoryLimit | int | `2` | Number of old revisions to retain | +| securityContext | map | `{}` | Security context to apply to the container | +| selectorLabels | map | `nil` | Will completely override the selectorLabels defined in the common chart's _label_setup.tpl | +| service | map | `{"port":80,"type":"ClusterIP"}` | Kubernetes service information. | +| service.port | int | `80` | The port number that the service exposes. | +| service.type | string | `"ClusterIP"` | Type of service. Valid values are "ClusterIP", "NodePort", "LoadBalancer", "ExternalName". | +| serviceAccount | map | `{"annotations":{},"create":true,"name":""}` | Service account to use or create. | +| serviceAccount.annotations | map | `{}` | Annotations to add to the service account. | +| serviceAccount.create | bool | `true` | Specifies whether a service account should be created. | +| serviceAccount.name | string | `""` | The name of the service account to use. If not set and create is true, a name is generated using the fullname template | +| strategy | map | `{"rollingUpdate":{"maxSurge":2,"maxUnavailable":"25%"},"type":"RollingUpdate"}` | Rolling update deployment strategy | +| strategy.rollingUpdate.maxSurge | int | `2` | Number of additional replicas to add during rollout. | +| strategy.rollingUpdate.maxUnavailable | int | `"25%"` | Maximum amount of pods that can be unavailable during the update. | +| tolerations | list | `[]` | Tolerations to apply to the pod | + diff --git a/helm/frontend-framework/templates/NOTES.txt b/helm/frontend-framework/templates/NOTES.txt new file mode 100644 index 00000000..c1e7e1ae --- /dev/null +++ b/helm/frontend-framework/templates/NOTES.txt @@ -0,0 +1 @@ +{{ .Chart.Name }} has been deployed successfully. diff --git a/helm/frontend-framework/templates/_helpers.tpl b/helm/frontend-framework/templates/_helpers.tpl new file mode 100644 index 00000000..851e1655 --- /dev/null +++ b/helm/frontend-framework/templates/_helpers.tpl @@ -0,0 +1,79 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "frontend-framework.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 "frontend-framework.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 "frontend-framework.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "frontend-framework.labels" -}} +{{- if .Values.commonLabels }} + {{- with .Values.commonLabels }} + {{- toYaml . }} + {{- end }} +{{- else }} + {{- (include "common.commonLabels" .)}} +{{- end }} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "frontend-framework.selectorLabels" -}} +{{- if .Values.selectorLabels }} + {{- with .Values.selectorLabels }} + {{- toYaml . }} + {{- end }} +{{- else }} + {{- (include "common.selectorLabels" .)}} +{{- end }} +{{- end }} + +{{/* +Create the name of the service account to use +*/}} +{{- define "frontend-framework.serviceAccountName" -}} +{{- if .Values.serviceAccount.create }} +{{- default (include "frontend-framework.fullname" .) .Values.serviceAccount.name }} +{{- else }} +{{- default "default" .Values.serviceAccount.name }} +{{- end }} +{{- end }} + +{{/* +Define tierAccessLevel +*/}} +{{- define "frontend-framework.tierAccessLevel" -}} +{{- if .Values.global }} +{{- .Values.global.tierAccessLevel }} +{{- else}} +{{- .Values.tierAccessLevel }} +{{- end }} +{{- end }} \ No newline at end of file diff --git a/helm/frontend-framework/templates/deployment.yaml b/helm/frontend-framework/templates/deployment.yaml new file mode 100644 index 00000000..ccb18398 --- /dev/null +++ b/helm/frontend-framework/templates/deployment.yaml @@ -0,0 +1,101 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: frontend-framework-deployment + labels: + {{- include "frontend-framework.labels" . | nindent 4 }} + {{- if .Values.global.ddEnabled }} + {{- include "common.datadogLabels" . | nindent 4 }} + {{- end }} +spec: + selector: + matchLabels: + {{- include "frontend-framework.selectorLabels" . | nindent 6 }} + revisionHistoryLimit: {{ .Values.revisionHistoryLimit }} + + strategy: + {{- toYaml .Values.strategy | nindent 8 }} + template: + metadata: + {{- with .Values.podAnnotations }} + annotations: + {{- toYaml . | nindent 8 }} + {{- end }} + labels: + {{- include "frontend-framework.selectorLabels" . | nindent 8 }} + public: "yes" + {{- if .Values.global.ddEnabled }} + {{- include "common.datadogLabels" . | nindent 8 }} + {{- end }} + spec: + {{- with .Values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + automountServiceAccountToken: {{ .Values.automountServiceAccountToken}} + containers: + - name: frontend-framework + image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + # livenessProbe: + # httpGet: + # path: /ff + # port: 80 + # initialDelaySeconds: 60 + # periodSeconds: 30 + # timeoutSeconds: 30 + # failureThreshold: 30 + readinessProbe: + httpGet: + {{- if eq "portal" .Values.global.frontendRoot }} + path: /ff + {{- else }} + path: / + {{- end }} + port: 3000 + initialDelaySeconds: 30 + periodSeconds: 60 + timeoutSeconds: 30 + resources: + {{- toYaml .Values.resources | nindent 12 }} + ports: + - containerPort: 80 + name: http + protocol: TCP + env: + {{- if .Values.global.ddEnabled }} + {{- include "common.datadogEnvVar" . | nindent 12 }} + {{- end }} + - name: HOSTNAME + value: revproxy-service + {{- if eq "portal" .Values.global.frontendRoot }} + - name: BASE_PATH + value: /ff + {{- else}} + - name: NEXT_PUBLIC_PORTAL_BASENAME + value: /portal + {{- end }} + # disable npm 7's brand new update notifier to prevent Portal from stuck at starting up + # see https://github.com/npm/cli/issues/3163 + - name: NPM_CONFIG_UPDATE_NOTIFIER + value: "false" +#needed to be adjusted to use the gen3 umbrella chart or local var ^ +#adding a var in helpers.tpl for later- Elise + {{- with .Values.datadogApplicationId }} + - name: DATADOG_APPLICATION_ID + # Optional client token for Datadog + value: {{ . }} + {{- end }} + {{- with .Values.datadogClientToken }} + - name: DATADOG_CLIENT_TOKEN + # Optional client token for Datadog + value: {{ . }} + {{- end }} + {{- with .Values.dataUploadBucket }} + - name: DATA_UPLOAD_BUCKET + value: {{ . }} + {{- end }} + # S3 bucket name for data upload, for setting up CSP + #GEN3_DATA_UPLOAD_BUCKET|-value: ""-| + # - name: BASENAME + diff --git a/helm/frontend-framework/templates/service.yaml b/helm/frontend-framework/templates/service.yaml new file mode 100644 index 00000000..c8742312 --- /dev/null +++ b/helm/frontend-framework/templates/service.yaml @@ -0,0 +1,19 @@ +apiVersion: v1 +kind: Service +metadata: + name: "frontend-framework-service" + labels: + {{- include "frontend-framework.labels" . | nindent 4 }} +spec: + ports: + - protocol: TCP + port: 80 + targetPort: 3000 + name: http + - protocol: TCP + port: 443 + targetPort: 3000 + name: https + type: ClusterIP + selector: + {{- include "frontend-framework.selectorLabels" . | nindent 4 }} diff --git a/helm/frontend-framework/templates/serviceaccount.yaml b/helm/frontend-framework/templates/serviceaccount.yaml new file mode 100644 index 00000000..5357e89e --- /dev/null +++ b/helm/frontend-framework/templates/serviceaccount.yaml @@ -0,0 +1,12 @@ +{{- if .Values.serviceAccount.create -}} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "frontend-framework.serviceAccountName" . }} + labels: + {{- include "frontend-framework.labels" . | nindent 4 }} + {{- with .Values.serviceAccount.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +{{- end }} diff --git a/helm/frontend-framework/values.yaml b/helm/frontend-framework/values.yaml new file mode 100644 index 00000000..03bb3777 --- /dev/null +++ b/helm/frontend-framework/values.yaml @@ -0,0 +1,198 @@ +# Default values for frontend-framework. +# This is a YAML-formatted file. +# Declare variables to be passed into your templates. +# -- (map) Global configuration options. +global: + # -- (map) AWS configuration + aws: + # -- (bool) Set to true if deploying to AWS. Controls ingress annotations. + enabled: false + # -- (string) Credentials for AWS stuff. + awsAccessKeyId: + # -- (string) Credentials for AWS stuff. + awsSecretAccessKey: + # -- (bool) Whether the deployment is for development purposes. + dev: true + # -- (map) Postgres database configuration. + postgres: + # -- (bool) Whether the database should be created. + dbCreate: true + # -- (map) Master credentials to postgres. This is going to be the default postgres server being used for each service, unless each service specifies their own postgres + master: + # -- (string) hostname of postgres server + host: + # -- (string) username of superuser in postgres. This is used to create or restore databases + username: postgres + # -- (string) password for superuser in postgres. This is used to create or restore databases + password: + # -- (string) Port for Postgres. + port: "5432" + # -- (string) Environment name. This should be the same as vpcname if you're doing an AWS deployment. Currently this is being used to share ALB's if you have multiple namespaces. Might be used other places too. + environment: default + # -- (string) Hostname for the deployment. + hostname: localhost + # -- (string) ARN of the reverse proxy certificate. + revproxyArn: arn:aws:acm:us-east-1:123456:certificate + # -- (string) URL of the data dictionary. + dictionaryUrl: https://s3.amazonaws.com/dictionary-artifacts/datadictionary/develop/schema.json + # -- (string) Portal application name. + portalApp: gitops + # -- (string) S3 bucket name for Kubernetes manifest files. + kubeBucket: kube-gen3 + # -- (string) S3 bucket name for log files. + logsBucket: logs-gen3 + # -- (bool) Whether to sync data from dbGaP. + syncFromDbgap: false + # -- (string) Path to the user.yaml file in S3. + userYamlS3Path: s3://cdis-gen3-users/test/user.yaml + # -- (bool) Whether public datasets are enabled. + publicDataSets: true + # -- (string) Access level for tiers. acceptable values for `tier_access_level` are: `libre`, `regular` and `private`. If omitted, by default common will be treated as `private`. + tierAccessLevel: libre + # -- (bool) Whether network policies are enabled. + netPolicy: true + # -- (int) Number of dispatcher jobs. + dispatcherJobNum: 10 + # -- (bool) Whether Datadog is enabled. + ddEnabled: false + +# -- (int) Number of replicas for the deployment. +replicaCount: 1 + +# -- (map) Docker image information. +image: + # -- (string) Docker repository. + repository: quay.io/cdis/frontend-framework + # -- (string) Docker pull policy. + pullPolicy: Always + # -- (string) Overrides the image tag whose default is the chart appVersion. + tag: "develop" + +# -- (list) Docker image pull secrets. +imagePullSecrets: [] + +# -- (string) Override the name of the chart. +nameOverride: "" + +# -- (string) Override the full name of the deployment. +fullnameOverride: "" + +# -- (map) Service account to use or create. +serviceAccount: + # -- (bool) Specifies whether a service account should be created. + create: true + # -- (map) Annotations to add to the service account. + annotations: {} + # -- (string) The name of the service account to use. + # If not set and create is true, a name is generated using the fullname template + name: "" + +# -- (map) Annotations to add to the pod +podAnnotations: {} + +# -- (map) Security context to apply to the pod +podSecurityContext: {} + # fsGroup: 2000 + +# -- (map) Security context to apply to the container +securityContext: {} + # capabilities: + # drop: + # - ALL + # readOnlyRootFilesystem: true + # runAsNonRoot: true + # runAsUser: 1000 + +# -- (map) Kubernetes service information. +service: + # -- (string) Type of service. Valid values are "ClusterIP", "NodePort", "LoadBalancer", "ExternalName". + type: ClusterIP + # -- (int) The port number that the service exposes. + port: 80 + +# -- (map) Configuration for autoscaling the number of replicas +autoscaling: + # -- (bool) Whether autoscaling is enabled + enabled: false + # -- (int) The minimum number of replicas to scale down to + minReplicas: 1 + # -- (int) The maximum number of replicas to scale up to + maxReplicas: 100 + # -- (int) The target CPU utilization percentage for autoscaling + targetCPUUtilizationPercentage: 80 + # targetMemoryUtilizationPercentage: 80 + +# -- (map) Node selector to apply to the pod +nodeSelector: {} + +# -- (list) Tolerations to apply to the pod +tolerations: [] + +# -- (int) Number of old revisions to retain +revisionHistoryLimit: 2 + +# -- (map) Rolling update deployment strategy +strategy: + type: RollingUpdate + rollingUpdate: + # -- (int) Number of additional replicas to add during rollout. + maxSurge: 2 + # -- (int) Maximum amount of pods that can be unavailable during the update. + maxUnavailable: 25% + +# -- (map) Affinity to use for the deployment. +affinity: + podAntiAffinity: + # -- (map) Option for scheduling to be required or preferred. + preferredDuringSchedulingIgnoredDuringExecution: + # -- (int) Weight value for preferred scheduling. + - weight: 100 + podAffinityTerm: + labelSelector: + matchExpressions: + # -- (list) Label key for match expression. + - key: app + # -- (string) Operation type for the match expression. + operator: In + # -- (list) Value for the match expression key. + values: + - frontend-framework + # -- (string) Value for topology key label. + topologyKey: "kubernetes.io/hostname" + +# -- (bool) Automount the default service account token +automountServiceAccountToken: false + +# -- (map) Resource requests and limits for the containers in the pod +resources: + # -- (map) The amount of resources that the container requests + requests: + # -- (string) The amount of CPU requested + cpu: 0.6 + # -- (string) The amount of memory requested + memory: 512Mi + # -- (map) The maximum amount of resources that the container is allowed to use + limits: + # -- (string) The maximum amount of memory the container can use + cpu: 0.6 + memory: 4096Mi + +# Values to determine the labels that are used for the deployment, pod, etc. +# -- (string) Valid options are "production" or "dev". If invalid option is set- the value will default to "dev". +release: "dev" +# -- (string) Valid options are "true" or "false". If invalid option is set- the value will default to "false". +criticalService: "true" +# -- (string) Label to help organize pods and their use. Any value is valid, but use "_" or "-" to divide words. +partOf: "Front-End" +# -- (map) Will completely override the selectorLabels defined in the common chart's _label_setup.tpl +selectorLabels: +# -- (map) Will completely override the commonLabels defined in the common chart's _label_setup.tpl +commonLabels: + +# Values to configure datadog if ddEnabled is set to "true". +# -- (bool) If enabled, the Datadog Agent will automatically inject Datadog-specific metadata into your application logs. +datadogLogsInjection: false +# -- (bool) If enabled, the Datadog Agent will collect profiling data for your application using the Continuous Profiler. This data can be used to identify performance bottlenecks and optimize your application. +datadogProfilingEnabled: false +# -- (int) A value between 0 and 1, that represents the percentage of requests that will be traced. For example, a value of 0.5 means that 50% of requests will be traced. +datadogTraceSampleRate: 1 diff --git a/helm/gen3/Chart.yaml b/helm/gen3/Chart.yaml index 259fb435..ccedae64 100644 --- a/helm/gen3/Chart.yaml +++ b/helm/gen3/Chart.yaml @@ -2,97 +2,100 @@ apiVersion: v2 name: gen3 description: Helm chart to deploy Gen3 Data Commons -# Dependancies +# Dependencies dependencies: - name: ambassador - version: 0.1.9 + version: 0.1.11 repository: "file://../ambassador" condition: ambassador.enabled - name: arborist - version: 0.1.9 + version: 0.1.11 repository: "file://../arborist" condition: arborist.enabled - name: argo-wrapper - version: 0.1.5 + version: 0.1.7 repository: "file://../argo-wrapper" condition: argo-wrapper.enabled - name: audit - version: 0.1.10 + version: 0.1.12 repository: "file://../audit" condition: audit.enabled - name: aws-es-proxy - version: 0.1.7 + version: 0.1.9 repository: "file://../aws-es-proxy" condition: aws-es-proxy.enabled - name: common - version: 0.1.8 + version: 0.1.11 repository: file://../common - name: etl - version: 0.1.0 + version: 0.1.1 repository: file://../etl condition: etl.enabled +- name: frontend-framework + version: 0.1.1 + repository: "file://../frontend-framework" + condition: frontend-framework.enabled - name: fence - version: 0.1.14 + version: 0.1.19 repository: "file://../fence" condition: fence.enabled - name: guppy - version: 0.1.9 + version: 0.1.12 repository: "file://../guppy" condition: guppy.enabled - name: hatchery - version: 0.1.7 + version: 0.1.9 repository: "file://../hatchery" condition: hatchery.enabled - name: indexd - version: 0.1.11 + version: 0.1.14 repository: "file://../indexd" condition: indexd.enabled - name: manifestservice - version: 0.1.11 + version: 0.1.14 repository: "file://../manifestservice" condition: manifestservice.enabled - name: metadata - version: 0.1.9 + version: 0.1.12 repository: "file://../metadata" condition: metadata.enabled - name: peregrine - version: 0.1.10 + version: 0.1.13 repository: "file://../peregrine" condition: peregrine.enabled - name: pidgin - version: 0.1.8 + version: 0.1.10 repository: "file://../pidgin" condition: pidgin.enabled - name: portal - version: 0.1.8 + version: 0.1.15 repository: "file://../portal" condition: portal.enabled - name: requestor - version: 0.1.9 + version: 0.1.11 repository: "file://../requestor" condition: requestor.enabled - name: revproxy - version: 0.1.12 + version: 0.1.16 repository: "file://../revproxy" condition: revproxy.enabled - name: sheepdog - version: 0.1.11 + version: 0.1.14 repository: "file://../sheepdog" condition: sheepdog.enabled - name: ssjdispatcher - version: 0.1.7 + version: 0.1.9 repository: "file://../ssjdispatcher" condition: ssjdispatcher.enabled - name: sower - version: 0.1.7 + version: 0.1.11 condition: sower.enabled repository: "file://../sower" - name: wts - version: 0.1.11 + version: 0.1.13 repository: "file://../wts" condition: wts.enabled - - name: elasticsearch version: 7.10.2 repository: "https://helm.elastic.co" @@ -102,6 +105,16 @@ dependencies: repository: "https://charts.bitnami.com/bitnami" condition: global.dev +# (optional) NeuVector Kubernetes Security Policy templates to protect Gen3 +# NeuVector must be installed separately. +# Reference: https://open-docs.neuvector.com/basics/overview +# Reference: https://github.com/neuvector/neuvector-helm +# For more information, please use the Gen3 community Slack. +- name: neuvector + version: "0.1.0" + repository: "file://../neuvector" + condition: neuvector.enabled + # A chart can be either an 'application' or a 'library' chart. # # Application charts are a collection of templates that can be packaged into versioned archives @@ -115,7 +128,7 @@ type: application # This is the chart version. This version number should be incremented each time you make changes # to the chart and its templates, including the app version. # Versions are expected to follow Semantic Versioning (https://semver.org/) -version: 0.1.21 +version: 0.1.38 # This is the version number of the application being deployed. This version number should be # incremented each time you make changes to the application. Versions are not expected to diff --git a/helm/gen3/README.md b/helm/gen3/README.md index 220a9cc4..fa6ed288 100644 --- a/helm/gen3/README.md +++ b/helm/gen3/README.md @@ -1,6 +1,6 @@ # gen3 -![Version: 0.1.21](https://img.shields.io/badge/Version-0.1.21-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: master](https://img.shields.io/badge/AppVersion-master-informational?style=flat-square) +![Version: 0.1.38](https://img.shields.io/badge/Version-0.1.38-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: master](https://img.shields.io/badge/AppVersion-master-informational?style=flat-square) Helm chart to deploy Gen3 Data Commons @@ -18,28 +18,30 @@ Helm chart to deploy Gen3 Data Commons | Repository | Name | Version | |------------|------|---------| -| file://../ambassador | ambassador | 0.1.9 | -| file://../arborist | arborist | 0.1.9 | -| file://../argo-wrapper | argo-wrapper | 0.1.5 | -| file://../audit | audit | 0.1.10 | -| file://../aws-es-proxy | aws-es-proxy | 0.1.7 | -| file://../common | common | 0.1.8 | -| file://../etl | etl | 0.1.0 | -| file://../fence | fence | 0.1.14 | -| file://../guppy | guppy | 0.1.9 | -| file://../hatchery | hatchery | 0.1.7 | -| file://../indexd | indexd | 0.1.11 | -| file://../manifestservice | manifestservice | 0.1.11 | -| file://../metadata | metadata | 0.1.9 | -| file://../peregrine | peregrine | 0.1.10 | -| file://../pidgin | pidgin | 0.1.8 | -| file://../portal | portal | 0.1.8 | -| file://../requestor | requestor | 0.1.9 | -| file://../revproxy | revproxy | 0.1.12 | -| file://../sheepdog | sheepdog | 0.1.11 | -| file://../sower | sower | 0.1.7 | -| file://../ssjdispatcher | ssjdispatcher | 0.1.7 | -| file://../wts | wts | 0.1.11 | +| file://../ambassador | ambassador | 0.1.11 | +| file://../arborist | arborist | 0.1.11 | +| file://../argo-wrapper | argo-wrapper | 0.1.7 | +| file://../audit | audit | 0.1.12 | +| file://../aws-es-proxy | aws-es-proxy | 0.1.9 | +| file://../common | common | 0.1.11 | +| file://../etl | etl | 0.1.1 | +| file://../fence | fence | 0.1.19 | +| file://../frontend-framework | frontend-framework | 0.1.1 | +| file://../guppy | guppy | 0.1.12 | +| file://../hatchery | hatchery | 0.1.9 | +| file://../indexd | indexd | 0.1.14 | +| file://../manifestservice | manifestservice | 0.1.14 | +| file://../metadata | metadata | 0.1.12 | +| file://../neuvector | neuvector | 0.1.0 | +| file://../peregrine | peregrine | 0.1.13 | +| file://../pidgin | pidgin | 0.1.10 | +| file://../portal | portal | 0.1.15 | +| file://../requestor | requestor | 0.1.11 | +| file://../revproxy | revproxy | 0.1.16 | +| file://../sheepdog | sheepdog | 0.1.14 | +| file://../sower | sower | 0.1.11 | +| file://../ssjdispatcher | ssjdispatcher | 0.1.9 | +| file://../wts | wts | 0.1.13 | | https://charts.bitnami.com/bitnami | postgresql | 11.9.13 | | https://helm.elastic.co | elasticsearch | 7.10.2 | @@ -48,20 +50,9 @@ Helm chart to deploy Gen3 Data Commons | Key | Type | Default | Description | |-----|------|---------|-------------| | ambassador.enabled | bool | `true` | Whether to deploy the ambassador subchart. | -| ambassador.image.repository | string | `nil` | The Docker image repository for the ambassador service. | -| ambassador.image.tag | string | `nil` | Overrides the image tag whose default is the chart appVersion. | | arborist.enabled | bool | `true` | Whether to deploy the arborist subchart. | -| arborist.image | map | `{"repository":null,"tag":null}` | Docker image information. | -| arborist.image.repository | string | `nil` | The Docker image repository for the arborist service. | -| arborist.image.tag | string | `nil` | Overrides the image tag whose default is the chart appVersion. | -| argo-wrapper.enabled | bool | `true` | Whether to deploy the argo-wrapper subchart. | -| argo-wrapper.image | map | `{"repository":null,"tag":null}` | Docker image information. | -| argo-wrapper.image.repository | string | `nil` | The Docker image repository for the argo-wrapper service. | -| argo-wrapper.image.tag | string | `nil` | Overrides the image tag whose default is the chart appVersion. | +| argo-wrapper.enabled | bool | `false` | Whether to deploy the argo-wrapper subchart. | | audit.enabled | bool | `true` | Whether to deploy the audit subchart. | -| audit.image | map | `{"repository":null,"tag":null}` | Docker image information. | -| audit.image.repository | string | `nil` | The Docker image repository for the audit service. | -| audit.image.tag | string | `nil` | Overrides the image tag whose default is the chart appVersion. | | aws-es-proxy.enabled | bool | `false` | Whether to deploy the aws-es-proxy subchart. | | aws-es-proxy.esEndpoint | str | `"test.us-east-1.es.amazonaws.com"` | Elasticsearch endpoint in AWS | | aws-es-proxy.secrets | map | `{"awsAccessKeyId":"","awsSecretAccessKey":""}` | Secret information | @@ -74,38 +65,44 @@ Helm chart to deploy Gen3 Data Commons | elasticsearch.replicas | int | `1` | | | elasticsearch.singleNode | bool | `true` | | | etl.enabled | bool | `true` | Whether to deploy the etl subchart. | -| fence.FENCE_CONFIG | map | `nil` | Configuration settings for Fence app | -| fence.USER_YAML | string | `nil` | USER YAML. Passed in as a multiline string. | | fence.enabled | bool | `true` | Whether to deploy the fence subchart. | -| fence.image | map | `{"repository":null,"tag":null}` | Docker image information. | -| fence.image.repository | string | `nil` | The Docker image repository for the fence service. | -| fence.image.tag | string | `nil` | Overrides the image tag whose default is the chart appVersion. | -| fence.usersync | map | `{"addDbgap":false,"custom_image":null,"onlyDbgap":false,"schedule":"*/30 * * * *","secrets":{"awsAccessKeyId":"","awsSecretAccessKey":""},"slack_send_dbgap":false,"slack_webhook":"None","syncFromDbgap":false,"userYamlS3Path":"s3://cdis-gen3-users/helm-test/user.yaml","usersync":false}` | Configuration options for usersync cronjob. | +| fence.usersync | map | `{"addDbgap":false,"onlyDbgap":false,"schedule":"*/30 * * * *","slack_send_dbgap":false,"slack_webhook":"None","syncFromDbgap":false,"userYamlS3Path":"s3://cdis-gen3-users/helm-test/user.yaml","usersync":false}` | Configuration options for usersync cronjob. | | fence.usersync.addDbgap | bool | `false` | Force attempting a dbgap sync if "true", falls back on user.yaml | -| fence.usersync.custom_image | string | `nil` | To set a custom image for pulling the user.yaml file from S3. Default is the Gen3 Awshelper image. | | fence.usersync.onlyDbgap | bool | `false` | Forces ONLY a dbgap sync if "true", IGNORING user.yaml | | fence.usersync.schedule | string | `"*/30 * * * *"` | The cron schedule expression to use in the usersync cronjob. Runs every 30 minutes by default. | -| fence.usersync.secrets | map | `{"awsAccessKeyId":"","awsSecretAccessKey":""}` | Secret information | -| fence.usersync.secrets.awsAccessKeyId | str | `""` | AWS access key ID for usersync S3 bucket | -| fence.usersync.secrets.awsSecretAccessKey | str | `""` | AWS secret access key for usersync S3 bucket | | fence.usersync.slack_send_dbgap | bool | `false` | Will echo what files we are seeing on dbgap ftp to Slack. | | fence.usersync.slack_webhook | string | `"None"` | Slack webhook endpoint used with certain jobs. | | fence.usersync.syncFromDbgap | bool | `false` | Whether to sync data from dbGaP. | | fence.usersync.userYamlS3Path | string | `"s3://cdis-gen3-users/helm-test/user.yaml"` | Path to the user.yaml file in S3. | | fence.usersync.usersync | bool | `false` | Whether to run Fence usersync or not. | -| gitops.createdby | string | `nil` | - createdby.png - base64 | -| gitops.css | string | `nil` | - multiline string - gitops.css | -| gitops.favicon | string | `nil` | - favicon in base64 | -| gitops.json | string | `nil` | multiline string - gitops.json | -| gitops.logo | string | `nil` | - logo in base64 | -| gitops.sponsors | string | `nil` | | -| global.aws | map | `{"enabled":false}` | AWS configuration | +| frontend-framework | map | `{"enabled":false,"image":{"repository":"quay.io/cdis/frontend-framework","tag":"develop"}}` | Configurations for frontend-framework chart. | +| frontend-framework.enabled | bool | `false` | Whether to deploy the frontend-framework subchart. | +| frontend-framework.image | map | `{"repository":"quay.io/cdis/frontend-framework","tag":"develop"}` | Docker image information. | +| frontend-framework.image.repository | string | `"quay.io/cdis/frontend-framework"` | The Docker image repository for the frontend-framework. | +| frontend-framework.image.tag | string | `"develop"` | Overrides the image tag whose default is the chart appVersion. | +| global.aws | map | `{"awsAccessKeyId":null,"awsSecretAccessKey":null,"enabled":false,"region":"us-east-1","secretStoreServiceAccount":{"enabled":false,"name":"secret-store-sa","roleArn":null},"useLocalSecret":{"enabled":false,"localSecretName":null}}` | AWS configuration | +| global.aws.awsAccessKeyId | string | `nil` | Credentials for AWS stuff. | +| global.aws.awsSecretAccessKey | string | `nil` | Credentials for AWS stuff. | +| global.aws.enabled | bool | `false` | Set to true if deploying to AWS. Controls ingress annotations. | +| global.aws.region | string | `"us-east-1"` | AWS region for this deployment | +| global.aws.secretStoreServiceAccount | map | `{"enabled":false,"name":"secret-store-sa","roleArn":null}` | Service account and AWS role for authentication to AWS Secrets Manager | +| global.aws.secretStoreServiceAccount.enabled | bool | `false` | Set true if deploying to AWS and want to use service account and IAM role instead of aws keys. Must provide role-arn. | +| global.aws.secretStoreServiceAccount.name | string | `"secret-store-sa"` | Name of the service account to create | +| global.aws.secretStoreServiceAccount.roleArn | string | `nil` | AWS Role ARN for Secret Store to use | +| global.aws.useLocalSecret | map | `{"enabled":false,"localSecretName":null}` | Local secret setting if using a pre-exising secret. | +| global.aws.useLocalSecret.enabled | bool | `false` | Set to true if you would like to use a secret that is already running on your cluster. | +| global.aws.useLocalSecret.localSecretName | string | `nil` | Name of the local secret. | | global.ddEnabled | bool | `false` | Whether Datadog is enabled. | | global.dev | bool | `true` | Deploys postgres/elasticsearch for dev | | global.dictionaryUrl | string | `"https://s3.amazonaws.com/dictionary-artifacts/datadictionary/develop/schema.json"` | URL of the data dictionary. | -| global.dispatcherJobNum | int | `10` | Number of dispatcher jobs. | +| global.dispatcherJobNum | int | `"10"` | Number of dispatcher jobs. | | global.environment | string | `"default"` | Environment name. This should be the same as vpcname if you're doing an AWS deployment. Currently this is being used to share ALB's if you have multiple namespaces in same cluster. | +| global.externalSecrets | map | `{"dbCreate":false,"deploy":false}` | External Secrets settings. | +| global.externalSecrets.dbCreate | bool | `false` | Will create the databases and store the creds in Kubernetes Secrets even if externalSecrets is deployed. Useful if you want to use ExternalSecrets for other secrets besides db secrets. | +| global.externalSecrets.deploy | bool | `false` | Will use ExternalSecret resources to pull secrets from Secrets Manager instead of creating them locally. Be cautious as this will override secrets you have deployed. | +| global.frontendRoot | string | `"portal"` | Which app will be served on /. Needs be set to portal for portal, or "gen3ff" for frontendframework. | | global.hostname | string | `"localhost"` | Hostname for the deployment. | +| global.manifestGlobalExtraValues | map | `{}` | If you would like to add any extra values to the manifest-global configmap. | | global.netPolicy | bool | `true` | Whether network policies are enabled. | | global.portalApp | string | `"gitops"` | Portal application name. | | global.postgres.dbCreate | bool | `true` | Whether the database create job should run. | @@ -117,10 +114,8 @@ Helm chart to deploy Gen3 Data Commons | global.revproxyArn | string | `"arn:aws:acm:us-east-1:123456:certificate"` | ARN of the reverse proxy certificate. | | global.tierAccessLevel | string | `"libre"` | Access level for tiers. acceptable values for `tier_access_level` are: `libre`, `regular` and `private`. If omitted, by default common will be treated as `private` | | global.tierAccessLimit | int | `"1000"` | Only relevant if tireAccessLevel is set to "regular". Summary charts below this limit will not appear for aggregated data. | +| guppy | map | `{"enabled":false}` | Configurations for guppy chart. | | guppy.enabled | bool | `false` | Whether to deploy the guppy subchart. | -| guppy.image | map | `{"repository":null,"tag":null}` | Docker image information. | -| guppy.image.repository | string | `nil` | The Docker image repository for the guppy service. | -| guppy.image.tag | string | `nil` | Overrides the image tag whose default is the chart appVersion. | | hatchery.enabled | bool | `true` | Whether to deploy the hatchery subchart. | | hatchery.hatchery.containers[0].args[0] | string | `"--NotebookApp.base_url=/lw-workspace/proxy/"` | | | hatchery.hatchery.containers[0].args[1] | string | `"--NotebookApp.default_url=/lab"` | | @@ -157,63 +152,30 @@ Helm chart to deploy Gen3 Data Commons | hatchery.hatchery.sidecarContainer.lifecycle-pre-stop[4] | string | `"/bin/sh"` | | | hatchery.hatchery.sidecarContainer.lifecycle-pre-stop[5] | string | `"root"` | | | hatchery.hatchery.sidecarContainer.memory-limit | string | `"256Mi"` | The maximum amount of memory the sidecar container can use | -| hatchery.image | map | `{"repository":null,"tag":null}` | Docker image information. | -| hatchery.image.repository | string | `nil` | The Docker image repository for the hatchery service. | -| hatchery.image.tag | string | `nil` | Overrides the image tag whose default is the chart appVersion. | | indexd.defaultPrefix | string | `"PREFIX/"` | the default prefix for indexd records | | indexd.enabled | bool | `true` | Whether to deploy the indexd subchart. | -| indexd.image | map | `{"repository":null,"tag":null}` | Docker image information. | -| indexd.image.repository | string | `nil` | The Docker image repository for the indexd service. | -| indexd.image.tag | string | `nil` | Overrides the image tag whose default is the chart appVersion. | | manifestservice.enabled | bool | `true` | Whether to deploy the manifest service subchart. | -| manifestservice.image | map | `{"repository":null,"tag":null}` | Docker image information. | -| manifestservice.image.repository | string | `nil` | The Docker image repository for the manifest service service. | -| manifestservice.image.tag | string | `nil` | Overrides the image tag whose default is the chart appVersion. | | metadata.enabled | bool | `true` | Whether to deploy the metadata subchart. | -| metadata.image | map | `{"repository":null,"tag":null}` | Docker image information. | -| metadata.image.repository | string | `nil` | The Docker image repository for the metadata service. | -| metadata.image.tag | string | `nil` | Overrides the image tag whose default is the chart appVersion. | +| neuvector.DB_HOST | string | `"development-gen3-postgresql"` | | +| neuvector.ES_HOST | string | `"gen3-elasticsearch-master"` | | +| neuvector.enabled | bool | `false` | | +| neuvector.ingress.class | string | `"nginx"` | | +| neuvector.ingress.controller | string | `"nginx-ingress-controller"` | | +| neuvector.ingress.namespace | string | `"nginx"` | | +| neuvector.policies.include | bool | `false` | | +| neuvector.policies.policyMode | string | `"Monitor"` | | | peregrine.enabled | bool | `true` | Whether to deploy the peregrine subchart. | -| peregrine.image | map | `{"repository":null,"tag":null}` | Docker image information. | -| peregrine.image.repository | string | `nil` | The Docker image repository for the peregrine service. | -| peregrine.image.tag | string | `nil` | Overrides the image tag whose default is the chart appVersion. | | pidgin.enabled | bool | `true` | Whether to deploy the pidgin subchart. | -| pidgin.image | map | `{"repository":null,"tag":null}` | Docker image information. | -| pidgin.image.repository | string | `nil` | The Docker image repository for the pidgin service. | -| pidgin.image.tag | string | `nil` | Overrides the image tag whose default is the chart appVersion. | | portal.enabled | bool | `true` | Whether to deploy the portal subchart. | -| portal.image | map | `{"repository":null,"tag":null}` | Docker image information. | -| portal.image.repository | string | `nil` | The Docker image repository for the portal service. | -| portal.image.tag | string | `nil` | Overrides the image tag whose default is the chart appVersion. | +| postgresql | map | `{"primary":{"persistence":{"enabled":false}}}` | To configure postgresql subchart Disable persistence by default so we can spin up and down ephemeral environments | | postgresql.primary.persistence.enabled | bool | `false` | Option to persist the dbs data. | | requestor.enabled | bool | `false` | Whether to deploy the requestor subchart. | -| requestor.image | map | `{"repository":null,"tag":null}` | Docker image information. | -| requestor.image.repository | string | `nil` | The Docker image repository for the requestor service. | -| requestor.image.tag | string | `nil` | Overrides the image tag whose default is the chart appVersion. | | revproxy.enabled | bool | `true` | Whether to deploy the revproxy subchart. | -| revproxy.image | map | `{"repository":null,"tag":null}` | Docker image information. | -| revproxy.image.repository | string | `nil` | The Docker image repository for the revproxy service. | -| revproxy.image.tag | string | `nil` | Overrides the image tag whose default is the chart appVersion. | | revproxy.ingress.annotations | map | `{}` | Annotations to add to the ingress. | -| revproxy.ingress.className | string | `""` | The ingress class name. | | revproxy.ingress.enabled | bool | `false` | Whether to create the custom revproxy ingress | | revproxy.ingress.hosts | list | `[{"host":"chart-example.local"}]` | Where to route the traffic. | | revproxy.ingress.tls | list | `[]` | To secure an Ingress by specifying a secret that contains a TLS private key and certificate. | -| secrets | map | `{"awsAccessKeyId":"test","awsSecretAccessKey":"test"}` | AWS credentials to access the db restore job S3 bucket | -| secrets.awsAccessKeyId | string | `"test"` | AWS access key. | -| secrets.awsSecretAccessKey | string | `"test"` | AWS secret access key. | | sheepdog.enabled | bool | `true` | Whether to deploy the sheepdog subchart. | -| sheepdog.image | map | `{"repository":null,"tag":null}` | Docker image information. | -| sheepdog.image.repository | string | `nil` | The Docker image repository for the sheepdog service. | -| sheepdog.image.tag | string | `nil` | Overrides the image tag whose default is the chart appVersion. | | ssjdispatcher.enabled | bool | `false` | Whether to deploy the ssjdispatcher subchart. | -| ssjdispatcher.image | map | `{"repository":null,"tag":null}` | Docker image information. | -| ssjdispatcher.image.repository | string | `nil` | The Docker image repository for the ssjdispatcher service. | -| ssjdispatcher.image.tag | string | `nil` | Overrides the image tag whose default is the chart appVersion. | | wts.enabled | bool | `true` | Whether to deploy the wts subchart. | -| wts.image | map | `{"repository":null,"tag":null}` | Docker image information. | -| wts.image.repository | string | `nil` | The Docker image repository for the wts service. | -| wts.image.tag | string | `nil` | Overrides the image tag whose default is the chart appVersion. | ----------------------------------------------- -Autogenerated from chart metadata using [helm-docs v1.11.0](https://github.com/norwoodj/helm-docs/releases/v1.11.0) diff --git a/helm/gen3/templates/aws-config.yaml b/helm/gen3/templates/aws-config.yaml new file mode 100644 index 00000000..bec10059 --- /dev/null +++ b/helm/gen3/templates/aws-config.yaml @@ -0,0 +1,3 @@ +{{- if and .Values.global.aws.awsSecretAccessKey (not .Values.global.aws.useLocalSecret.enabled) }} +{{ include "common.awsconfig" . }} +{{- end -}} \ No newline at end of file diff --git a/helm/gen3/templates/aws_config.yaml b/helm/gen3/templates/aws_config.yaml deleted file mode 100644 index 3b51159c..00000000 --- a/helm/gen3/templates/aws_config.yaml +++ /dev/null @@ -1,10 +0,0 @@ -apiVersion: v1 -kind: Secret -metadata: - name: aws-config -type: Opaque -stringData: - credentials: | - [default] - aws_access_key_id={{.Values.secrets.awsAccessKeyId}} - aws_secret_access_key={{ .Values.secrets.awsSecretAccessKey}} \ No newline at end of file diff --git a/helm/gen3/templates/cluster-secret-store.yaml b/helm/gen3/templates/cluster-secret-store.yaml new file mode 100644 index 00000000..28ffe29e --- /dev/null +++ b/helm/gen3/templates/cluster-secret-store.yaml @@ -0,0 +1,21 @@ +{{- if and .Values.global.externalSecrets.deploy (not .Values.global.aws.useLocalSecret.enabled) }} +{{ include "common.secretstore" . }} +{{- else if .Values.global.aws.useLocalSecret.enabled }} +apiVersion: external-secrets.io/v1beta1 +kind: SecretStore +metadata: + name: {{.Chart.Name}}-secret-store +spec: + provider: + aws: + service: SecretsManager + region: {{ .Values.global.aws.region }} + auth: + secretRef: + accessKeyIDSecretRef: + name: {{ .Values.global.aws.useLocalSecret.localSecretName }} + key: access-key + secretAccessKeySecretRef: + name: {{ .Values.global.aws.useLocalSecret.localSecretName }} + key: secret-access-key +{{- end }} \ No newline at end of file diff --git a/helm/gen3/templates/global-manifest.yaml b/helm/gen3/templates/global-manifest.yaml index 945088d5..24842a25 100644 --- a/helm/gen3/templates/global-manifest.yaml +++ b/helm/gen3/templates/global-manifest.yaml @@ -14,6 +14,12 @@ data: "netpolicy": {{ .Values.global.netPolicy | quote }} "dispatcher_job_num": {{ .Values.global.dispatcherJobNum | quote }} "dd_enabled": {{ .Values.global.ddEnabled | quote }} + "frontend_root": {{ .Values.global.frontendRoot | quote }} {{- with .Values.global.origins_allow_credentials }} "origins_allow_credentials": {{ . | toJson | quote }} - {{- end -}} \ No newline at end of file + {{- end -}} + {{- with .Values.global.manifestGlobalExtraValues }} + {{- range $key, $value := . }} + {{ $key }}: {{ $value | quote }} + {{- end }} + {{- end }} \ No newline at end of file diff --git a/helm/gen3/templates/secret-store-service-account.yaml b/helm/gen3/templates/secret-store-service-account.yaml new file mode 100644 index 00000000..0284bac4 --- /dev/null +++ b/helm/gen3/templates/secret-store-service-account.yaml @@ -0,0 +1,29 @@ +{{- if .Values.global.aws.secretStoreServiceAccount.enabled }} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ .Values.global.aws.secretStoreServiceAccount.name }} + annotations: + eks.amazonaws.com/role-arn: {{ .Values.global.aws.secretStoreServiceAccount.roleArn }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: external-secrets-role +rules: +- apiGroups: [""] + resources: ["secrets"] + verbs: ["*"] +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: external-secrets-rolebinding +subjects: +- kind: ServiceAccount + name: {{ .Values.global.aws.secretStoreServiceAccount.name }} +roleRef: + kind: Role + name: external-secrets-role + apiGroup: rbac.authorization.k8s.io +{{- end }} \ No newline at end of file diff --git a/helm/gen3/values.yaml b/helm/gen3/values.yaml index 0bb20303..e5f528b2 100644 --- a/helm/gen3/values.yaml +++ b/helm/gen3/values.yaml @@ -2,16 +2,32 @@ # This is a YAML-formatted file. # Declare variables to be passed into your templates. +# Global configuration global: # -- (map) AWS configuration aws: + # -- (string) AWS region for this deployment + region: us-east-1 + # -- (bool) Set to true if deploying to AWS. Controls ingress annotations. enabled: false - # # -- (map) Credentials for AWS - # account: - # # Prep move of these keys here. - # aws_access_key_id: - # aws_secret_access_key: - + # -- (string) Credentials for AWS stuff. + awsAccessKeyId: + # -- (string) Credentials for AWS stuff. + awsSecretAccessKey: + # -- (map) Service account and AWS role for authentication to AWS Secrets Manager + secretStoreServiceAccount: + # -- (bool) Set true if deploying to AWS and want to use service account and IAM role instead of aws keys. Must provide role-arn. + enabled: false + # -- (string) Name of the service account to create + name: secret-store-sa + # -- (string) AWS Role ARN for Secret Store to use + roleArn: + # -- (map) Local secret setting if using a pre-exising secret. + useLocalSecret: + # -- (bool) Set to true if you would like to use a secret that is already running on your cluster. + enabled: false + # -- (string) Name of the local secret. + localSecretName: # -- (bool) Deploys postgres/elasticsearch for dev dev: true postgres: @@ -47,51 +63,37 @@ global: # -- (bool) Whether network policies are enabled. netPolicy: true # -- (int) Number of dispatcher jobs. - dispatcherJobNum: 10 + dispatcherJobNum: "10" # -- (bool) Whether Datadog is enabled. ddEnabled: false - + # -- (map) If you would like to add any extra values to the manifest-global configmap. + manifestGlobalExtraValues: {} + # -- (string) Which app will be served on /. Needs be set to portal for portal, or "gen3ff" for frontendframework. + frontendRoot: "portal" + # -- (map) External Secrets settings. + externalSecrets: + # -- (bool) Will use ExternalSecret resources to pull secrets from Secrets Manager instead of creating them locally. Be cautious as this will override secrets you have deployed. + deploy: false + # -- (bool) Will create the databases and store the creds in Kubernetes Secrets even if externalSecrets is deployed. Useful if you want to use ExternalSecrets for other secrets besides db secrets. + dbCreate: false # Dependancy Charts ambassador: # -- (bool) Whether to deploy the ambassador subchart. enabled: true - image: - # -- (string) The Docker image repository for the ambassador service. - repository: - # -- (string) Overrides the image tag whose default is the chart appVersion. - tag: arborist: # -- (bool) Whether to deploy the arborist subchart. enabled: true - # -- (map) Docker image information. - image: - # -- (string) The Docker image repository for the arborist service. - repository: - # -- (string) Overrides the image tag whose default is the chart appVersion. - tag: argo-wrapper: # -- (bool) Whether to deploy the argo-wrapper subchart. - enabled: true - # -- (map) Docker image information. - image: - # -- (string) The Docker image repository for the argo-wrapper service. - repository: - # -- (string) Overrides the image tag whose default is the chart appVersion. - tag: + enabled: false audit: # -- (bool) Whether to deploy the audit subchart. enabled: true - # -- (map) Docker image information. - image: - # -- (string) The Docker image repository for the audit service. - repository: - # -- (string) Overrides the image tag whose default is the chart appVersion. - tag: aws-es-proxy: @@ -113,30 +115,12 @@ etl: fence: # -- (bool) Whether to deploy the fence subchart. enabled: true - # -- (map) Docker image information. - image: - # -- (string) The Docker image repository for the fence service. - repository: - # -- (string) Overrides the image tag whose default is the chart appVersion. - tag: - # -- (map) Configuration settings for Fence app - FENCE_CONFIG: - # -- (string) USER YAML. Passed in as a multiline string. - USER_YAML: # -- (map) Configuration options for usersync cronjob. usersync: # -- (bool) Whether to run Fence usersync or not. usersync: false - # -- (map) Secret information - secrets: - # -- (str) AWS access key ID for usersync S3 bucket - awsAccessKeyId: "" - # -- (str) AWS secret access key for usersync S3 bucket - awsSecretAccessKey: "" # -- (string) The cron schedule expression to use in the usersync cronjob. Runs every 30 minutes by default. schedule: "*/30 * * * *" - # -- (string) To set a custom image for pulling the user.yaml file from S3. Default is the Gen3 Awshelper image. - custom_image: # -- (bool) Whether to sync data from dbGaP. syncFromDbgap: false # -- (bool) Force attempting a dbgap sync if "true", falls back on user.yaml @@ -150,25 +134,25 @@ fence: # -- (bool) Will echo what files we are seeing on dbgap ftp to Slack. slack_send_dbgap: false -guppy: - # -- (bool) Whether to deploy the guppy subchart. +# -- (map) Configurations for frontend-framework chart. +frontend-framework: + # -- (bool) Whether to deploy the frontend-framework subchart. enabled: false # -- (map) Docker image information. image: - # -- (string) The Docker image repository for the guppy service. - repository: + # -- (string) The Docker image repository for the frontend-framework. + repository: "quay.io/cdis/frontend-framework" # -- (string) Overrides the image tag whose default is the chart appVersion. - tag: + tag: "develop" + +# -- (map) Configurations for guppy chart. +guppy: + # -- (bool) Whether to deploy the guppy subchart. + enabled: false hatchery: # -- (bool) Whether to deploy the hatchery subchart. enabled: true - # -- (map) Docker image information. - image: - # -- (string) The Docker image repository for the hatchery service. - repository: - # -- (string) Overrides the image tag whose default is the chart appVersion. - tag: hatchery: sidecarContainer: @@ -236,12 +220,6 @@ hatchery: indexd: # -- (bool) Whether to deploy the indexd subchart. enabled: true - # -- (map) Docker image information. - image: - # -- (string) The Docker image repository for the indexd service. - repository: - # -- (string) Overrides the image tag whose default is the chart appVersion. - tag: # -- (string) the default prefix for indexd records defaultPrefix: "PREFIX/" @@ -249,92 +227,35 @@ indexd: manifestservice: # -- (bool) Whether to deploy the manifest service subchart. enabled: true - # -- (map) Docker image information. - image: - # -- (string) The Docker image repository for the manifest service service. - repository: - # -- (string) Overrides the image tag whose default is the chart appVersion. - tag: metadata: # -- (bool) Whether to deploy the metadata subchart. enabled: true - # -- (map) Docker image information. - image: - # -- (string) The Docker image repository for the metadata service. - repository: - # -- (string) Overrides the image tag whose default is the chart appVersion. - tag: peregrine: # -- (bool) Whether to deploy the peregrine subchart. enabled: true - # -- (map) Docker image information. - image: - # -- (string) The Docker image repository for the peregrine service. - repository: - # -- (string) Overrides the image tag whose default is the chart appVersion. - tag: pidgin: # -- (bool) Whether to deploy the pidgin subchart. enabled: true - # -- (map) Docker image information. - image: - # -- (string) The Docker image repository for the pidgin service. - repository: - # -- (string) Overrides the image tag whose default is the chart appVersion. - tag: portal: # -- (bool) Whether to deploy the portal subchart. enabled: true - # -- (map) Docker image information. - image: - # -- (string) The Docker image repository for the portal service. - repository: - # -- (string) Overrides the image tag whose default is the chart appVersion. - tag: - # -- (map) GitOps configuration for portal -gitops: - # -- (string) multiline string - gitops.json - json: - # -- (string) - favicon in base64 - favicon: - # -- (string) - multiline string - gitops.css - css: - # -- (string) - logo in base64 - logo: - # -- (string) - createdby.png - base64 - createdby: - sponsors: requestor: # -- (bool) Whether to deploy the requestor subchart. enabled: false - # -- (map) Docker image information. - image: - # -- (string) The Docker image repository for the requestor service. - repository: - # -- (string) Overrides the image tag whose default is the chart appVersion. - tag: revproxy: # -- (bool) Whether to deploy the revproxy subchart. enabled: true - # -- (map) Docker image information. - image: - # -- (string) The Docker image repository for the revproxy service. - repository: - # -- (string) Overrides the image tag whose default is the chart appVersion. - tag: ingress: # -- (bool) Whether to create the custom revproxy ingress enabled: false - # -- (string) The ingress class name. - className: "" # -- (map) Annotations to add to the ingress. annotations: {} # kubernetes.io/ingress.class: nginx @@ -348,41 +269,16 @@ revproxy: sheepdog: # -- (bool) Whether to deploy the sheepdog subchart. enabled: true - # -- (map) Docker image information. - image: - # -- (string) The Docker image repository for the sheepdog service. - repository: - # -- (string) Overrides the image tag whose default is the chart appVersion. - tag: ssjdispatcher: # -- (bool) Whether to deploy the ssjdispatcher subchart. enabled: false - # -- (map) Docker image information. - image: - # -- (string) The Docker image repository for the ssjdispatcher service. - repository: - # -- (string) Overrides the image tag whose default is the chart appVersion. - tag: - wts: # -- (bool) Whether to deploy the wts subchart. enabled: true - # -- (map) Docker image information. - image: - # -- (string) The Docker image repository for the wts service. - repository: - # -- (string) Overrides the image tag whose default is the chart appVersion. - tag: - -# -- (map) AWS credentials to access the db restore job S3 bucket -secrets: - # -- (string) AWS access key. - awsAccessKeyId: test - # -- (string) AWS secret access key. - awsSecretAccessKey: test +# -- (map) To configure postgresql subchart # Disable persistence by default so we can spin up and down ephemeral environments postgresql: primary: @@ -399,3 +295,29 @@ elasticsearch: esConfig: elasticsearch.yml: | # Here we can add elasticsearch config + +# (optional) NeuVector Kubernetes Security Policy templates to protect Gen3 +# NeuVector must be installed separately. +# Reference: https://open-docs.neuvector.com/basics/overview +# Reference: https://github.com/neuvector/neuvector-helm +# For more information, please use the Gen3 community Slack. +neuvector: + # install Neuvector + enabled: false + policies: + # deploy predefined Neuvector policies for Gen3 + include: false + # Discover, Monitor, or Protect + policyMode: Monitor + # Configure your ingress controller information for enabling ingress to containers + ingress: + # service name of your ingress controller + controller: nginx-ingress-controller + # installation namespace of your ingress controller + namespace: nginx + # classname of your ingress + class: nginx + # Required to allow egress to in-cluster database or external, managed database + DB_HOST: development-gen3-postgresql + # hostname/service name for our ElasitcSearch instance, used to allow egress from containers + ES_HOST: gen3-elasticsearch-master diff --git a/helm/guppy/Chart.yaml b/helm/guppy/Chart.yaml index 8243c558..20bd0f26 100644 --- a/helm/guppy/Chart.yaml +++ b/helm/guppy/Chart.yaml @@ -15,7 +15,7 @@ type: application # This is the chart version. This version number should be incremented each time you make changes # to the chart and its templates, including the app version. # Versions are expected to follow Semantic Versioning (https://semver.org/) -version: 0.1.9 +version: 0.1.12 # This is the version number of the application being deployed. This version number should be # incremented each time you make changes to the application. Versions are not expected to @@ -25,5 +25,5 @@ appVersion: "master" dependencies: - name: common - version: 0.1.8 + version: 0.1.11 repository: file://../common diff --git a/helm/guppy/README.md b/helm/guppy/README.md index a785aca3..fa5fa0e5 100644 --- a/helm/guppy/README.md +++ b/helm/guppy/README.md @@ -1,6 +1,6 @@ # guppy -![Version: 0.1.9](https://img.shields.io/badge/Version-0.1.9-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: master](https://img.shields.io/badge/AppVersion-master-informational?style=flat-square) +![Version: 0.1.12](https://img.shields.io/badge/Version-0.1.12-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: master](https://img.shields.io/badge/AppVersion-master-informational?style=flat-square) A Helm chart for gen3 Guppy Service @@ -8,7 +8,7 @@ A Helm chart for gen3 Guppy Service | Repository | Name | Version | |------------|------|---------| -| file://../common | common | 0.1.8 | +| file://../common | common | 0.1.11 | ## Values @@ -40,7 +40,6 @@ A Helm chart for gen3 Guppy Service | enableEncryptWhitelist | bool | `true` | Whether or not to enable encryption for specified fields | | encryptWhitelist | string | `"test1"` | A comma-separated list of fields to encrypt | | esEndpoint | string | `"gen3-elasticsearch-master:9200"` | Elasticsearch endpoint. | -| global | map | `{"aws":{"awsAccessKeyId":null,"awsSecretAccessKey":null,"enabled":false},"ddEnabled":false,"dev":true,"dictionaryUrl":"https://s3.amazonaws.com/dictionary-artifacts/datadictionary/develop/schema.json","dispatcherJobNum":"10","environment":"default","hostname":"localhost","kubeBucket":"kube-gen3","logsBucket":"logs-gen3","minAvialable":1,"netPolicy":true,"pdb":false,"portalApp":"gitops","postgres":{"dbCreate":true,"master":{"host":null,"password":null,"port":"5432","username":"postgres"}},"publicDataSets":true,"revproxyArn":"arn:aws:acm:us-east-1:123456:certificate","tierAccessLevel":"libre","tierAccessLimit":"1000"}` | Global configuration options. | | global.aws | map | `{"awsAccessKeyId":null,"awsSecretAccessKey":null,"enabled":false}` | AWS configuration | | global.aws.awsAccessKeyId | string | `nil` | Credentials for AWS stuff. | | global.aws.awsSecretAccessKey | string | `nil` | Credentials for AWS stuff. | @@ -57,8 +56,8 @@ A Helm chart for gen3 Guppy Service | global.netPolicy | bool | `true` | Whether network policies are enabled. | | global.pdb | bool | `false` | If the service will be deployed with a Pod Disruption Budget. Note- you need to have more than 2 replicas for the pdb to be deployed. | | global.portalApp | string | `"gitops"` | Portal application name. | -| global.postgres | map | `{"dbCreate":true,"master":{"host":null,"password":null,"port":"5432","username":"postgres"}}` | Postgres database configuration. | | global.postgres.dbCreate | bool | `true` | Whether the database should be created. | +| global.postgres.externalSecret | string | `""` | Name of external secret. Disabled if empty | | global.postgres.master | map | `{"host":null,"password":null,"port":"5432","username":"postgres"}` | Master credentials to postgres. This is going to be the default postgres server being used for each service, unless each service specifies their own postgres | | global.postgres.master.host | string | `nil` | hostname of postgres server | | global.postgres.master.password | string | `nil` | password for superuser in postgres. This is used to create or restore databases | @@ -84,9 +83,9 @@ A Helm chart for gen3 Guppy Service | resources.requests.cpu | string | `0.1` | The amount of CPU requested | | resources.requests.memory | string | `"500Mi"` | The amount of memory requested | | revisionHistoryLimit | int | `2` | Number of old revisions to retain | -| secrets | map | `{"awsAccessKeyId":null,"awsSecretAccessKey":null}` | AWS credentials to access the db restore job S3 bucket | -| secrets.awsAccessKeyId | string | `nil` | AWS access key. | -| secrets.awsSecretAccessKey | string | `nil` | AWS secret access key. | +| secrets | map | `{"awsAccessKeyId":null,"awsSecretAccessKey":null}` | Secret information to access the db restore job S3 bucket. | +| secrets.awsAccessKeyId | str | `nil` | AWS access key ID. Overrides global key. | +| secrets.awsSecretAccessKey | str | `nil` | AWS secret access key ID. Overrides global key. | | selectorLabels | map | `nil` | Will completely override the selectorLabels defined in the common chart's _label_setup.tpl | | service | map | `{"port":[{"name":"http","port":80,"protocol":"TCP","targetPort":8000}],"type":"ClusterIP"}` | Kubernetes service information. | | service.port | int | `[{"name":"http","port":80,"protocol":"TCP","targetPort":8000}]` | The port number that the service exposes. | @@ -97,5 +96,3 @@ A Helm chart for gen3 Guppy Service | volumeMounts | list | `[{"mountPath":"/guppy/guppy_config.json","name":"guppy-config","readOnly":true,"subPath":"guppy_config.json"}]` | Volumes to mount to the container. | | volumes | list | `[{"configMap":{"items":[{"key":"guppy_config.json","path":"guppy_config.json"}],"name":"manifest-guppy"},"name":"guppy-config"}]` | Volumes to attach to the pod. | ----------------------------------------------- -Autogenerated from chart metadata using [helm-docs v1.11.0](https://github.com/norwoodj/helm-docs/releases/v1.11.0) diff --git a/helm/guppy/templates/aws-config.yaml b/helm/guppy/templates/aws-config.yaml new file mode 100644 index 00000000..4723e6b3 --- /dev/null +++ b/helm/guppy/templates/aws-config.yaml @@ -0,0 +1,3 @@ +{{- if or (.Values.secrets.awsSecretAccessKey) (.Values.global.aws.awsSecretAccessKey ) }} +{{ include "common.awsconfig" . }} +{{- end }} \ No newline at end of file diff --git a/helm/guppy/templates/aws-creds.yaml b/helm/guppy/templates/aws-creds.yaml deleted file mode 100644 index 77f70daf..00000000 --- a/helm/guppy/templates/aws-creds.yaml +++ /dev/null @@ -1,13 +0,0 @@ -{{- if or (.Values.secrets.awsSecretAccessKey) (.Values.global.aws.awsSecretAccessKey ) }} -apiVersion: v1 -kind: Secret -metadata: - name: aws-config-guppy -type: Opaque -stringData: - credentials: | - [default] - aws_access_key_id={{ .Values.secrets.awsAccessKeyId | default .Values.global.aws.awsAccessKeyId }} - aws_secret_access_key={{ .Values.secrets.awsSecretAccessKey | default .Values.global.aws.awsSecretAccessKey }} -{{- end }} - diff --git a/helm/guppy/templates/deployment.yaml b/helm/guppy/templates/deployment.yaml index 8a1e16d8..552f9063 100644 --- a/helm/guppy/templates/deployment.yaml +++ b/helm/guppy/templates/deployment.yaml @@ -71,7 +71,7 @@ spec: value: {{ . }} {{- end }} - name: TIER_ACCESS_LEVEL - value: {{ .Values.global.tierAccessLevel }} + value: {{ .Values.global.tierAccessLevel | quote }} - name: TIER_ACCESS_LIMIT value: {{ .Values.global.tierAccessLimit | quote }} {{- with .Values.volumeMounts }} diff --git a/helm/guppy/templates/guppy_config.yaml b/helm/guppy/templates/guppy_config.yaml index ff7ab9be..ad8bcd40 100644 --- a/helm/guppy/templates/guppy_config.yaml +++ b/helm/guppy/templates/guppy_config.yaml @@ -6,9 +6,7 @@ data: guppy_config.json: | { "indices": {{ .Values.indices | toJson }}, - {{- with .Values.configIndex }} - "config_index": {{ . | quote }}, - {{- end }} + "config_index": {{ .Values.configIndex | toJson }}, "auth_filter_field": {{ .Values.authFilterField | quote }}, "enable_encrypt_whitelist": {{ .Values.enableEncryptWhitelist | quote }}, "encrypt_whitelist": {{ .Values.encryptWhitelist | quote }} diff --git a/helm/guppy/values.yaml b/helm/guppy/values.yaml index a8465f80..054e4734 100644 --- a/helm/guppy/values.yaml +++ b/helm/guppy/values.yaml @@ -2,7 +2,8 @@ # This is a YAML-formatted file. # Declare variables to be passed into your templates. -# -- (map) Global configuration options. + +# Global configuration global: # -- (map) AWS configuration aws: @@ -14,10 +15,12 @@ global: awsSecretAccessKey: # -- (bool) Whether the deployment is for development purposes. dev: true - # -- (map) Postgres database configuration. + postgres: # -- (bool) Whether the database should be created. dbCreate: true + # -- (string) Name of external secret. Disabled if empty + externalSecret: "" # -- (map) Master credentials to postgres. This is going to be the default postgres server being used for each service, unless each service specifies their own postgres master: # -- (string) hostname of postgres server @@ -70,11 +73,11 @@ autoscaling: # -- (int) The target CPU utilization percentage for autoscaling targetCPUUtilizationPercentage: 80 -# -- (map) AWS credentials to access the db restore job S3 bucket +# -- (map) Secret information to access the db restore job S3 bucket. secrets: - # -- (string) AWS access key. + # -- (str) AWS access key ID. Overrides global key. awsAccessKeyId: - # -- (string) AWS secret access key. + # -- (str) AWS secret access key ID. Overrides global key. awsSecretAccessKey: # -- (int) Number of replicas for the deployment. diff --git a/helm/hatchery/Chart.yaml b/helm/hatchery/Chart.yaml index bb311c95..8e4c05c1 100644 --- a/helm/hatchery/Chart.yaml +++ b/helm/hatchery/Chart.yaml @@ -15,7 +15,7 @@ type: application # This is the chart version. This version number should be incremented each time you make changes # to the chart and its templates, including the app version. # Versions are expected to follow Semantic Versioning (https://semver.org/) -version: 0.1.7 +version: 0.1.9 # This is the version number of the application being deployed. This version number should be # incremented each time you make changes to the application. Versions are not expected to @@ -25,5 +25,5 @@ appVersion: "master" dependencies: - name: common - version: 0.1.8 + version: 0.1.10 repository: file://../common diff --git a/helm/hatchery/README.md b/helm/hatchery/README.md index 4e7bfe3c..3ebadfc2 100644 --- a/helm/hatchery/README.md +++ b/helm/hatchery/README.md @@ -1,6 +1,6 @@ # hatchery -![Version: 0.1.7](https://img.shields.io/badge/Version-0.1.7-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: master](https://img.shields.io/badge/AppVersion-master-informational?style=flat-square) +![Version: 0.1.9](https://img.shields.io/badge/Version-0.1.9-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: master](https://img.shields.io/badge/AppVersion-master-informational?style=flat-square) A Helm chart for gen3 Hatchery @@ -8,7 +8,7 @@ A Helm chart for gen3 Hatchery | Repository | Name | Version | |------------|------|---------| -| file://../common | common | 0.1.8 | +| file://../common | common | 0.1.10 | ## Values @@ -27,7 +27,6 @@ A Helm chart for gen3 Hatchery | datadogTraceSampleRate | int | `1` | A value between 0 and 1, that represents the percentage of requests that will be traced. For example, a value of 0.5 means that 50% of requests will be traced. | | env | list | `[{"name":"HTTP_PORT","value":"8000"},{"name":"POD_NAMESPACE","valueFrom":{"fieldRef":{"fieldPath":"metadata.namespace"}}}]` | Environment variables to pass to the container | | fullnameOverride | string | `""` | Override the full name of the deployment. | -| global | map | `{"aws":{"awsAccessKeyId":null,"awsSecretAccessKey":null,"enabled":false},"ddEnabled":false,"dev":true,"dictionaryUrl":"https://s3.amazonaws.com/dictionary-artifacts/datadictionary/develop/schema.json","dispatcherJobNum":10,"environment":"default","hostname":"localhost","kubeBucket":"kube-gen3","logsBucket":"logs-gen3","minAvialable":1,"netPolicy":true,"pdb":false,"portalApp":"gitops","postgres":{"dbCreate":true,"master":{"host":null,"password":null,"port":"5432","username":"postgres"}},"publicDataSets":true,"revproxyArn":"arn:aws:acm:us-east-1:123456:certificate","tierAccessLevel":"libre"}` | Global configuration options. | | global.aws | map | `{"awsAccessKeyId":null,"awsSecretAccessKey":null,"enabled":false}` | AWS configuration | | global.aws.awsAccessKeyId | string | `nil` | Credentials for AWS stuff. | | global.aws.awsSecretAccessKey | string | `nil` | Credentials for AWS stuff. | @@ -35,7 +34,7 @@ A Helm chart for gen3 Hatchery | global.ddEnabled | bool | `false` | Whether Datadog is enabled. | | global.dev | bool | `true` | Whether the deployment is for development purposes. | | global.dictionaryUrl | string | `"https://s3.amazonaws.com/dictionary-artifacts/datadictionary/develop/schema.json"` | URL of the data dictionary. | -| global.dispatcherJobNum | int | `10` | Number of dispatcher jobs. | +| global.dispatcherJobNum | int | `"10"` | Number of dispatcher jobs. | | global.environment | string | `"default"` | Environment name. This should be the same as vpcname if you're doing an AWS deployment. Currently this is being used to share ALB's if you have multiple namespaces. Might be used other places too. | | global.hostname | string | `"localhost"` | Hostname for the deployment. | | global.kubeBucket | string | `"kube-gen3"` | S3 bucket name for Kubernetes manifest files. | @@ -44,8 +43,8 @@ A Helm chart for gen3 Hatchery | global.netPolicy | bool | `true` | Whether network policies are enabled. | | global.pdb | bool | `false` | If the service will be deployed with a Pod Disruption Budget. Note- you need to have more than 2 replicas for the pdb to be deployed. | | global.portalApp | string | `"gitops"` | Portal application name. | -| global.postgres | map | `{"dbCreate":true,"master":{"host":null,"password":null,"port":"5432","username":"postgres"}}` | Postgres database configuration. | | global.postgres.dbCreate | bool | `true` | Whether the database should be created. | +| global.postgres.externalSecret | string | `""` | Name of external secret. Disabled if empty | | global.postgres.master | map | `{"host":null,"password":null,"port":"5432","username":"postgres"}` | Master credentials to postgres. This is going to be the default postgres server being used for each service, unless each service specifies their own postgres | | global.postgres.master.host | string | `nil` | hostname of postgres server | | global.postgres.master.password | string | `nil` | password for superuser in postgres. This is used to create or restore databases | @@ -87,5 +86,3 @@ A Helm chart for gen3 Hatchery | volumeMounts | list | `[{"mountPath":"/hatchery.json","name":"hatchery-config","readOnly":true,"subPath":"json"}]` | Volumes to mount to the container. | | volumes | list | `[{"configMap":{"name":"manifest-hatchery"},"name":"hatchery-config"}]` | Volumes to attach to the container. | ----------------------------------------------- -Autogenerated from chart metadata using [helm-docs v1.11.0](https://github.com/norwoodj/helm-docs/releases/v1.11.0) diff --git a/helm/hatchery/values.yaml b/helm/hatchery/values.yaml index 27127335..739f9457 100644 --- a/helm/hatchery/values.yaml +++ b/helm/hatchery/values.yaml @@ -2,7 +2,8 @@ # This is a YAML-formatted file. # Declare variables to be passed into your templates. -# -- (map) Global configuration options. + +# Global configuration global: # -- (map) AWS configuration aws: @@ -14,10 +15,12 @@ global: awsSecretAccessKey: # -- (bool) Whether the deployment is for development purposes. dev: true - # -- (map) Postgres database configuration. + postgres: # -- (bool) Whether the database should be created. dbCreate: true + # -- (string) Name of external secret. Disabled if empty + externalSecret: "" # -- (map) Master credentials to postgres. This is going to be the default postgres server being used for each service, unless each service specifies their own postgres master: # -- (string) hostname of postgres server @@ -49,7 +52,7 @@ global: # -- (bool) Whether network policies are enabled. netPolicy: true # -- (int) Number of dispatcher jobs. - dispatcherJobNum: 10 + dispatcherJobNum: "10" # -- (bool) Whether Datadog is enabled. ddEnabled: false # -- (bool) If the service will be deployed with a Pod Disruption Budget. Note- you need to have more than 2 replicas for the pdb to be deployed. diff --git a/helm/indexd/Chart.yaml b/helm/indexd/Chart.yaml index c7b2b223..19e78126 100644 --- a/helm/indexd/Chart.yaml +++ b/helm/indexd/Chart.yaml @@ -15,7 +15,7 @@ type: application # This is the chart version. This version number should be incremented each time you make changes # to the chart and its templates, including the app version. # Versions are expected to follow Semantic Versioning (https://semver.org/) -version: 0.1.11 +version: 0.1.14 # This is the version number of the application being deployed. This version number should be # incremented each time you make changes to the application. Versions are not expected to @@ -26,7 +26,7 @@ appVersion: "master" dependencies: - name: common - version: 0.1.8 + version: 0.1.10 repository: file://../common - name: postgresql version: 11.9.13 diff --git a/helm/indexd/README.md b/helm/indexd/README.md index 8528ba92..b4e5ff79 100644 --- a/helm/indexd/README.md +++ b/helm/indexd/README.md @@ -1,6 +1,6 @@ # indexd -![Version: 0.1.11](https://img.shields.io/badge/Version-0.1.11-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: master](https://img.shields.io/badge/AppVersion-master-informational?style=flat-square) +![Version: 0.1.14](https://img.shields.io/badge/Version-0.1.14-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: master](https://img.shields.io/badge/AppVersion-master-informational?style=flat-square) A Helm chart for gen3 indexd @@ -8,7 +8,7 @@ A Helm chart for gen3 indexd | Repository | Name | Version | |------------|------|---------| -| file://../common | common | 0.1.8 | +| file://../common | common | 0.1.10 | | https://charts.bitnami.com/bitnami | postgresql | 11.9.13 | ## Values @@ -27,8 +27,10 @@ A Helm chart for gen3 indexd | datadogTraceSampleRate | int | `1` | A value between 0 and 1, that represents the percentage of requests that will be traced. For example, a value of 0.5 means that 50% of requests will be traced. | | defaultPrefix | string | `"PREFIX/"` | default prefix for indexd | | env | list | `[{"name":"ARBORIST","value":"true"},{"name":"GEN3_DEBUG","value":"False"}]` | Environment variables to pass to the container | +| externalSecrets | map | `{"createK8sServiceCredsSecret":false,"dbcreds":null,"serviceCreds":"indexd-service-creds"}` | External Secrets settings. | +| externalSecrets.createK8sServiceCredsSecret | string | `false` | Will create the Helm "indexd-service-creds" secret even if Secrets Manager is enabled. This is helpful if you are wanting to use External Secrets for some, but not all secrets. | +| externalSecrets.dbcreds | string | `nil` | Will override the name of the aws secrets manager secret. Default is "Values.global.environment-.Chart.Name-creds" | | fullnameOverride | string | `""` | Override the full name of the deployment. | -| global | map | `{"aws":{"awsAccessKeyId":null,"awsSecretAccessKey":null,"enabled":false},"ddEnabled":false,"dev":true,"dictionaryUrl":"https://s3.amazonaws.com/dictionary-artifacts/datadictionary/develop/schema.json","dispatcherJobNum":10,"environment":"default","hostname":"localhost","kubeBucket":"kube-gen3","logsBucket":"logs-gen3","minAvialable":1,"netPolicy":true,"pdb":false,"portalApp":"gitops","postgres":{"dbCreate":true,"master":{"host":null,"password":null,"port":"5432","username":"postgres"}},"publicDataSets":true,"revproxyArn":"arn:aws:acm:us-east-1:123456:certificate","tierAccessLevel":"libre","tierAccessLimit":1000}` | Global configuration options. | | global.aws | map | `{"awsAccessKeyId":null,"awsSecretAccessKey":null,"enabled":false}` | AWS configuration | | global.aws.awsAccessKeyId | string | `nil` | Credentials for AWS stuff. | | global.aws.awsSecretAccessKey | string | `nil` | Credentials for AWS stuff. | @@ -36,8 +38,11 @@ A Helm chart for gen3 indexd | global.ddEnabled | bool | `false` | Whether Datadog is enabled. | | global.dev | bool | `true` | Whether the deployment is for development purposes. | | global.dictionaryUrl | string | `"https://s3.amazonaws.com/dictionary-artifacts/datadictionary/develop/schema.json"` | URL of the data dictionary. | -| global.dispatcherJobNum | int | `10` | Number of dispatcher jobs. | +| global.dispatcherJobNum | int | `"10"` | Number of dispatcher jobs. | | global.environment | string | `"default"` | Environment name. This should be the same as vpcname if you're doing an AWS deployment. Currently this is being used to share ALB's if you have multiple namespaces. Might be used other places too. | +| global.externalSecrets | map | `{"deploy":false,"separateSecretStore":false}` | External Secrets settings. | +| global.externalSecrets.deploy | bool | `false` | Will use ExternalSecret resources to pull secrets from Secrets Manager instead of creating them locally. Be cautious as this will override any indexd secrets you have deployed. | +| global.externalSecrets.separateSecretStore | string | `false` | Will deploy a separate External Secret Store for this service. | | global.hostname | string | `"localhost"` | Hostname for the deployment. | | global.kubeBucket | string | `"kube-gen3"` | S3 bucket name for Kubernetes manifest files. | | global.logsBucket | string | `"logs-gen3"` | S3 bucket name for log files. | @@ -45,8 +50,8 @@ A Helm chart for gen3 indexd | global.netPolicy | bool | `true` | Whether network policies are enabled. | | global.pdb | bool | `false` | If the service will be deployed with a Pod Disruption Budget. Note- you need to have more than 2 replicas for the pdb to be deployed. | | global.portalApp | string | `"gitops"` | Portal application name. | -| global.postgres | map | `{"dbCreate":true,"master":{"host":null,"password":null,"port":"5432","username":"postgres"}}` | Postgres database configuration. | | global.postgres.dbCreate | bool | `true` | Whether the database should be created. | +| global.postgres.externalSecret | string | `""` | Name of external secret. Disabled if empty | | global.postgres.master | map | `{"host":null,"password":null,"port":"5432","username":"postgres"}` | Master credentials to postgres. This is going to be the default postgres server being used for each service, unless each service specifies their own postgres | | global.postgres.master.host | string | `nil` | hostname of postgres server | | global.postgres.master.password | string | `nil` | password for superuser in postgres. This is used to create or restore databases | @@ -55,7 +60,7 @@ A Helm chart for gen3 indexd | global.publicDataSets | bool | `true` | Whether public datasets are enabled. | | global.revproxyArn | string | `"arn:aws:acm:us-east-1:123456:certificate"` | ARN of the reverse proxy certificate. | | global.tierAccessLevel | string | `"libre"` | Access level for tiers. acceptable values for `tier_access_level` are: `libre`, `regular` and `private`. If omitted, by default common will be treated as `private` | -| global.tierAccessLimit | int | `1000` | Only relevant if tireAccessLevel is set to "regular". Summary charts below this limit will not appear for aggregated data. | +| global.tierAccessLimit | int | `"1000"` | Only relevant if tireAccessLevel is set to "regular". Summary charts below this limit will not appear for aggregated data. | | image | map | `{"pullPolicy":"IfNotPresent","repository":"quay.io/cdis/indexd","tag":""}` | Docker image information. | | image.pullPolicy | string | `"IfNotPresent"` | When to pull the image. | | image.repository | string | `"quay.io/cdis/indexd"` | The Docker image repository for the indexd service | @@ -85,7 +90,9 @@ A Helm chart for gen3 indexd | resources.requests | map | `{"cpu":0.1,"memory":"12Mi"}` | The amount of resources that the container requests | | resources.requests.cpu | string | `0.1` | The amount of CPU requested | | resources.requests.memory | string | `"12Mi"` | The amount of memory requested | -| secrets | map | `{"userdb":{"fence":null,"sheepdog":null}}` | Values for indexd secret. | +| secrets | map | `{"awsAccessKeyId":null,"awsSecretAccessKey":null,"userdb":{"fence":null,"sheepdog":null}}` | Values for indexd secret. | +| secrets.awsAccessKeyId | str | `nil` | AWS access key ID to access the db restore job S3 bucket. Overrides global key. | +| secrets.awsSecretAccessKey | str | `nil` | AWS secret access key ID to access the db restore job S3 bucket. Overrides global key. | | securityContext | map | `{}` | Security context for the containers in the pod | | selectorLabels | map | `nil` | Will completely override the selectorLabels defined in the common chart's _label_setup.tpl | | service | map | `{"port":80,"type":"ClusterIP"}` | Kubernetes service information. | @@ -103,5 +110,3 @@ A Helm chart for gen3 indexd | volumeMounts | list | `[{"mountPath":"/var/www/indexd/local_settings.py","name":"config-volume","readOnly":true,"subPath":"local_settings.py"}]` | Volumes to mount to the container. | | volumes | list | `[{"configMap":{"name":"indexd-wsgi"},"name":"wsgi-config"},{"name":"config-volume","secret":{"secretName":"indexd-settings"}},{"configMap":{"name":"indexd-nginx-configmap"},"name":"nginx-config"}]` | Volumes to attach to the pod | ----------------------------------------------- -Autogenerated from chart metadata using [helm-docs v1.11.0](https://github.com/norwoodj/helm-docs/releases/v1.11.0) diff --git a/helm/indexd/templates/_helpers.tpl b/helm/indexd/templates/_helpers.tpl index 0f83473c..5778d510 100644 --- a/helm/indexd/templates/_helpers.tpl +++ b/helm/indexd/templates/_helpers.tpl @@ -101,4 +101,4 @@ Create the name of the service account to use */}} {{- define "indexd-gateway-creds" -}} {{- default (randAlphaNum 32) .Values.secrets.userdb.gateway }} -{{- end }} \ No newline at end of file +{{- end }} diff --git a/helm/indexd/templates/aws-config.yaml b/helm/indexd/templates/aws-config.yaml new file mode 100644 index 00000000..4723e6b3 --- /dev/null +++ b/helm/indexd/templates/aws-config.yaml @@ -0,0 +1,3 @@ +{{- if or (.Values.secrets.awsSecretAccessKey) (.Values.global.aws.awsSecretAccessKey ) }} +{{ include "common.awsconfig" . }} +{{- end }} \ No newline at end of file diff --git a/helm/indexd/templates/external-secrets.yaml b/helm/indexd/templates/external-secrets.yaml new file mode 100644 index 00000000..b8cb2a38 --- /dev/null +++ b/helm/indexd/templates/external-secrets.yaml @@ -0,0 +1,21 @@ +{{ include "common.externalSecret.db" . }} +--- +{{ if .Values.global.externalSecrets.deploy }} +apiVersion: external-secrets.io/v1beta1 +kind: ExternalSecret +metadata: + name: indexd-service-creds +spec: + refreshInterval: 5m + secretStoreRef: + name: {{include "common.SecretStore" .}} + kind: SecretStore + target: + name: indexd-service-creds + creationPolicy: Owner + dataFrom: + - extract: + key: {{ .Values.externalSecrets.serviceCreds }} + conversionStrategy: Default + decodingStrategy: None +{{- end }} \ No newline at end of file diff --git a/helm/indexd/templates/indexd-secret.yaml b/helm/indexd/templates/indexd-secret.yaml index 7c7ca648..5b296ccf 100644 --- a/helm/indexd/templates/indexd-secret.yaml +++ b/helm/indexd/templates/indexd-secret.yaml @@ -6,6 +6,7 @@ type: Opaque data: {{ (.Files.Glob "indexd-settings/*").AsSecrets | indent 2 }} --- +{{- if or (not .Values.global.externalSecrets.deploy) (and .Values.global.externalSecrets.deploy .Values.externalSecrets.createK8sServiceCredsSecret) }} apiVersion: v1 kind: Secret metadata: @@ -14,3 +15,4 @@ type: Opaque data: fence: {{ include "common.getOrGenSecret" (list .Values.secrets.userdb.fence "indexd-service-creds" "fence" 20 .Release.Namespace) }} sheepdog: {{ include "common.getOrGenSecret" (list .Values.secrets.userdb.sheepdog "indexd-service-creds" "sheepdog" 20 .Release.Namespace) }} +{{- end }} \ No newline at end of file diff --git a/helm/indexd/templates/secret-store.yaml b/helm/indexd/templates/secret-store.yaml new file mode 100644 index 00000000..771c7760 --- /dev/null +++ b/helm/indexd/templates/secret-store.yaml @@ -0,0 +1,3 @@ +{{ if .Values.global.externalSecrets.separateSecretStore }} +{{ include "common.secretstore" . }} +{{- end }} \ No newline at end of file diff --git a/helm/indexd/values.yaml b/helm/indexd/values.yaml index f918e5bf..6d9c63db 100644 --- a/helm/indexd/values.yaml +++ b/helm/indexd/values.yaml @@ -2,7 +2,8 @@ # This is a YAML-formatted file. # Declare variables to be passed into your templates. -# -- (map) Global configuration options. + +# Global configuration global: # -- (map) AWS configuration aws: @@ -14,10 +15,12 @@ global: awsSecretAccessKey: # -- (bool) Whether the deployment is for development purposes. dev: true - # -- (map) Postgres database configuration. + postgres: # -- (bool) Whether the database should be created. dbCreate: true + # -- (string) Name of external secret. Disabled if empty + externalSecret: "" # -- (map) Master credentials to postgres. This is going to be the default postgres server being used for each service, unless each service specifies their own postgres master: # -- (string) hostname of postgres server @@ -47,17 +50,42 @@ global: # -- (string) Access level for tiers. acceptable values for `tier_access_level` are: `libre`, `regular` and `private`. If omitted, by default common will be treated as `private` tierAccessLevel: libre # -- (int) Only relevant if tireAccessLevel is set to "regular". Summary charts below this limit will not appear for aggregated data. - tierAccessLimit: 1000 + tierAccessLimit: "1000" # -- (bool) Whether network policies are enabled. netPolicy: true # -- (int) Number of dispatcher jobs. - dispatcherJobNum: 10 + dispatcherJobNum: "10" # -- (bool) Whether Datadog is enabled. ddEnabled: false # -- (bool) If the service will be deployed with a Pod Disruption Budget. Note- you need to have more than 2 replicas for the pdb to be deployed. pdb: false # -- (int) The minimum amount of pods that are available at all times if the PDB is deployed. minAvialable: 1 + # -- (map) External Secrets settings. + externalSecrets: + # -- (bool) Will use ExternalSecret resources to pull secrets from Secrets Manager instead of creating them locally. Be cautious as this will override any indexd secrets you have deployed. + deploy: false + # -- (string) Will deploy a separate External Secret Store for this service. + separateSecretStore: false + +# -- (map) External Secrets settings. +externalSecrets: + # -- (string) Will create the Helm "indexd-service-creds" secret even if Secrets Manager is enabled. This is helpful if you are wanting to use External Secrets for some, but not all secrets. + createK8sServiceCredsSecret: false + # -- (string) Will override the name of the aws secrets manager secret. Default is "Values.global.environment-.Chart.Name-creds" + dbcreds: + serviceCreds: "indexd-service-creds" + +# -- (map) Values for indexd secret. +secrets: + userdb: + fence: + sheepdog: + # gateway: + # -- (str) AWS access key ID to access the db restore job S3 bucket. Overrides global key. + awsAccessKeyId: + # -- (str) AWS secret access key ID to access the db restore job S3 bucket. Overrides global key. + awsSecretAccessKey: # -- (map) Postgres database configuration. If db does not exist in postgres cluster and dbCreate is set ot true then these databases will be created for you postgres: @@ -211,12 +239,9 @@ env: - name: "GEN3_DEBUG" value: "False" -# -- (map) Values for indexd secret. -secrets: - userdb: - fence: - sheepdog: - # gateway: +# -- (map) Values for overriding uwsgi settings +uwsgi: + listen: 1024 # -- (string) default prefix for indexd defaultPrefix: "PREFIX/" diff --git a/helm/manifestservice/Chart.yaml b/helm/manifestservice/Chart.yaml index 3b5eee3a..382e0165 100644 --- a/helm/manifestservice/Chart.yaml +++ b/helm/manifestservice/Chart.yaml @@ -15,7 +15,7 @@ type: application # This is the chart version. This version number should be incremented each time you make changes # to the chart and its templates, including the app version. # Versions are expected to follow Semantic Versioning (https://semver.org/) -version: 0.1.11 +version: 0.1.14 # This is the version number of the application being deployed. This version number should be # incremented each time you make changes to the application. Versions are not expected to @@ -25,5 +25,5 @@ appVersion: "master" dependencies: - name: common - version: 0.1.8 + version: 0.1.10 repository: file://../common diff --git a/helm/manifestservice/README.md b/helm/manifestservice/README.md index b35b0704..9e7df7f5 100644 --- a/helm/manifestservice/README.md +++ b/helm/manifestservice/README.md @@ -1,6 +1,6 @@ # manifestservice -![Version: 0.1.11](https://img.shields.io/badge/Version-0.1.11-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: master](https://img.shields.io/badge/AppVersion-master-informational?style=flat-square) +![Version: 0.1.14](https://img.shields.io/badge/Version-0.1.14-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: master](https://img.shields.io/badge/AppVersion-master-informational?style=flat-square) A Helm chart for Kubernetes @@ -8,7 +8,7 @@ A Helm chart for Kubernetes | Repository | Name | Version | |------------|------|---------| -| file://../common | common | 0.1.8 | +| file://../common | common | 0.1.10 | ## Values @@ -33,9 +33,18 @@ A Helm chart for Kubernetes | datadogProfilingEnabled | bool | `true` | If enabled, the Datadog Agent will collect profiling data for your application using the Continuous Profiler. This data can be used to identify performance bottlenecks and optimize your application. | | datadogTraceSampleRate | int | `1` | A value between 0 and 1, that represents the percentage of requests that will be traced. For example, a value of 0.5 means that 50% of requests will be traced. | | env | list | `[{"name":"REQUESTS_CA_BUNDLE","value":"/etc/ssl/certs/ca-certificates.crt"},{"name":"MANIFEST_SERVICE_CONFIG_PATH","value":"/var/gen3/config/config.json"},{"name":"GEN3_DEBUG","value":"False"}]` | Environment variables to pass to the container | -| global | map | `{"ddEnabled":false,"environment":"default","minAvialable":1,"pdb":false}` | Global configuration options. | +| externalSecrets | map | `{"createK8sManifestServiceSecret":false,"manifestserviceG3auto":null}` | External Secrets settings. | +| externalSecrets.createK8sManifestServiceSecret | string | `false` | Will create the Helm "manifestservice-g3auto" secret even if Secrets Manager is enabled. This is helpful if you are wanting to use External Secrets for some, but not all secrets. | +| externalSecrets.manifestserviceG3auto | string | `nil` | Will override the name of the aws secrets manager secret. Default is "manifestservice-g3auto" | +| global.aws | map | `{"awsAccessKeyId":null,"awsSecretAccessKey":null,"enabled":false}` | AWS configuration | +| global.aws.awsAccessKeyId | string | `nil` | Credentials for AWS stuff. | +| global.aws.awsSecretAccessKey | string | `nil` | Credentials for AWS stuff. | +| global.aws.enabled | bool | `false` | Set to true if deploying to AWS. Controls ingress annotations. | | global.ddEnabled | bool | `false` | Whether Datadog is enabled. | | global.environment | string | `"default"` | Environment name. This should be the same as vpcname if you're doing an AWS deployment. Currently this is being used to share ALB's if you have multiple namespaces. Might be used other places too. | +| global.externalSecrets | map | `{"deploy":false,"separateSecretStore":false}` | External Secrets settings. | +| global.externalSecrets.deploy | bool | `false` | Will use ExternalSecret resources to pull secrets from Secrets Manager instead of creating them locally. Be cautious as this will override any manifestservice secrets you have deployed. | +| global.externalSecrets.separateSecretStore | string | `false` | Will deploy a separate External Secret Store for this service. | | global.minAvialable | int | `1` | The minimum amount of pods that are available at all times if the PDB is deployed. | | global.pdb | bool | `false` | If the service will be deployed with a Pod Disruption Budget. Note- you need to have more than 2 replicas for the pdb to be deployed. | | image | map | `{"pullPolicy":"Always","repository":"quay.io/cdis/manifestservice","tag":""}` | Docker image information. | @@ -58,6 +67,9 @@ A Helm chart for Kubernetes | resources.requests.cpu | string | `0.1` | The amount of CPU requested | | resources.requests.memory | string | `"12Mi"` | The amount of memory requested | | revisionHistoryLimit | int | `2` | Number of old revisions to retain | +| secrets | map | `{"awsAccessKeyId":null,"awsSecretAccessKey":null}` | Secret information for External Secrets. | +| secrets.awsAccessKeyId | str | `nil` | AWS access key ID. Overrides global key. | +| secrets.awsSecretAccessKey | str | `nil` | AWS secret access key ID. Overrides global key. | | selectorLabels | map | `nil` | Will completely override the selectorLabels defined in the common chart's _label_setup.tpl | | service | map | `{"port":80,"type":"ClusterIP"}` | Kubernetes service information. | | service.port | int | `80` | The port number that the service exposes. | @@ -77,5 +89,3 @@ A Helm chart for Kubernetes | volumeMounts | list | `[{"mountPath":"/manifestservice/deployment/wsgi/gunicorn.conf.py","name":"wsgi-config","subPath":"gunicorn.conf.py"},{"mountPath":"/var/gen3/config/","name":"config-volume","readOnly":true}]` | Volumes to mount to the container. | | volumes | list | `[{"configMap":{"name":"manifestservice-wsgi"},"name":"wsgi-config"},{"name":"config-volume","secret":{"secretName":"manifestservice-g3auto"}},{"configMap":{"name":"manifestservice-nginx-configmap"},"name":"nginx-config"}]` | Volumes to attach to the container. | ----------------------------------------------- -Autogenerated from chart metadata using [helm-docs v1.11.0](https://github.com/norwoodj/helm-docs/releases/v1.11.0) diff --git a/helm/manifestservice/templates/_helpers.tpl b/helm/manifestservice/templates/_helpers.tpl index d0d72644..fb9b68c7 100644 --- a/helm/manifestservice/templates/_helpers.tpl +++ b/helm/manifestservice/templates/_helpers.tpl @@ -65,3 +65,10 @@ Create the name of the service account to use {{- default "default" .Values.serviceAccount.name }} {{- end }} {{- end }} + +{{/* + Audit g3 Auto Secrets Manager Name +*/}} +{{- define "manifestservice-g3auto" -}} +{{- default "manifestservice-g3auto" .Values.externalSecrets.manifestserviceG3auto }} +{{- end }} diff --git a/helm/manifestservice/templates/aws-config.yaml b/helm/manifestservice/templates/aws-config.yaml new file mode 100644 index 00000000..398770d3 --- /dev/null +++ b/helm/manifestservice/templates/aws-config.yaml @@ -0,0 +1,3 @@ +{{- if or (.Values.secrets.awsSecretAccessKey) (.Values.global.aws.awsSecretAccessKey ) }} +{{ include "common.awsconfig" . }} +{{- end -}} \ No newline at end of file diff --git a/helm/manifestservice/templates/external-secret.yaml b/helm/manifestservice/templates/external-secret.yaml new file mode 100644 index 00000000..7d94f5c9 --- /dev/null +++ b/helm/manifestservice/templates/external-secret.yaml @@ -0,0 +1,19 @@ +{{ if .Values.global.externalSecrets.deploy }} +apiVersion: external-secrets.io/v1beta1 +kind: ExternalSecret +metadata: + name: manifestservice-g3auto +spec: + refreshInterval: 5m + secretStoreRef: + name: {{include "common.SecretStore" .}} + kind: SecretStore + target: + name: manifestservice-g3auto + creationPolicy: Owner + data: + - secretKey: config.json + remoteRef: + #name of secret in secrets manager + key: {{include "manifestservice-g3auto" .}} +{{- end }} \ No newline at end of file diff --git a/helm/manifestservice/templates/metadataservice-creds.yaml b/helm/manifestservice/templates/manifestservice-creds.yaml similarity index 66% rename from helm/manifestservice/templates/metadataservice-creds.yaml rename to helm/manifestservice/templates/manifestservice-creds.yaml index 22dd070a..54c5f29a 100644 --- a/helm/manifestservice/templates/metadataservice-creds.yaml +++ b/helm/manifestservice/templates/manifestservice-creds.yaml @@ -1,3 +1,4 @@ +{{- if or (not .Values.global.externalSecrets.deploy) (and .Values.global.externalSecrets.deploy .Values.externalSecrets.createK8sManifestServiceSecret) }} apiVersion: v1 kind: Secret metadata: @@ -7,9 +8,9 @@ stringData: config.json: |- { "manifest_bucket_name": "{{ .Values.manifestserviceG3auto.bucketName }}", - "hostname": "{{ .Values.manifestserviceG3auto.hostname }}", + "hostname": "{{ .Values.global.hostname }}", "aws_access_key_id": "{{ .Values.manifestserviceG3auto.awsaccesskey }}", "aws_secret_access_key": "{{ .Values.manifestserviceG3auto.awssecretkey }}", "prefix": "{{ .Values.manifestserviceG3auto.prefix }}" } - +{{- end }} \ No newline at end of file diff --git a/helm/manifestservice/templates/secret-store.yaml b/helm/manifestservice/templates/secret-store.yaml new file mode 100644 index 00000000..771c7760 --- /dev/null +++ b/helm/manifestservice/templates/secret-store.yaml @@ -0,0 +1,3 @@ +{{ if .Values.global.externalSecrets.separateSecretStore }} +{{ include "common.secretstore" . }} +{{- end }} \ No newline at end of file diff --git a/helm/manifestservice/values.yaml b/helm/manifestservice/values.yaml index de780696..2ecd86cf 100644 --- a/helm/manifestservice/values.yaml +++ b/helm/manifestservice/values.yaml @@ -2,8 +2,17 @@ # This is a YAML-formatted file. # Declare variables to be passed into your templates. -# -- (map) Global configuration options. + +# Global configuration global: + # -- (map) AWS configuration + aws: + # -- (bool) Set to true if deploying to AWS. Controls ingress annotations. + enabled: false + # -- (string) Credentials for AWS stuff. + awsAccessKeyId: + # -- (string) Credentials for AWS stuff. + awsSecretAccessKey: # -- (string) Environment name. This should be the same as vpcname if you're doing an AWS deployment. Currently this is being used to share ALB's if you have multiple namespaces. Might be used other places too. environment: default # -- (bool) Whether Datadog is enabled. @@ -12,6 +21,25 @@ global: pdb: false # -- (int) The minimum amount of pods that are available at all times if the PDB is deployed. minAvialable: 1 + # -- (map) External Secrets settings. + externalSecrets: + # -- (bool) Will use ExternalSecret resources to pull secrets from Secrets Manager instead of creating them locally. Be cautious as this will override any manifestservice secrets you have deployed. + deploy: false + # -- (string) Will deploy a separate External Secret Store for this service. + separateSecretStore: false + +# -- (map) External Secrets settings. +externalSecrets: + # -- (string) Will create the Helm "manifestservice-g3auto" secret even if Secrets Manager is enabled. This is helpful if you are wanting to use External Secrets for some, but not all secrets. + createK8sManifestServiceSecret: false + # -- (string) Will override the name of the aws secrets manager secret. Default is "manifestservice-g3auto" + manifestserviceG3auto: +# -- (map) Secret information for External Secrets. +secrets: + # -- (str) AWS access key ID. Overrides global key. + awsAccessKeyId: + # -- (str) AWS secret access key ID. Overrides global key. + awsSecretAccessKey: # -- (int) Number of old revisions to retain revisionHistoryLimit: 2 diff --git a/helm/metadata/Chart.yaml b/helm/metadata/Chart.yaml index b0730575..d38d06e5 100644 --- a/helm/metadata/Chart.yaml +++ b/helm/metadata/Chart.yaml @@ -15,7 +15,7 @@ type: application # This is the chart version. This version number should be incremented each time you make changes # to the chart and its templates, including the app version. # Versions are expected to follow Semantic Versioning (https://semver.org/) -version: 0.1.9 +version: 0.1.12 # This is the version number of the application being deployed. This version number should be # incremented each time you make changes to the application. Versions are not expected to @@ -25,7 +25,7 @@ appVersion: "master" dependencies: - name: common - version: 0.1.8 + version: 0.1.10 repository: file://../common - name: postgresql version: 11.9.13 diff --git a/helm/metadata/README.md b/helm/metadata/README.md index 7a66aad3..7fe7be69 100644 --- a/helm/metadata/README.md +++ b/helm/metadata/README.md @@ -1,6 +1,6 @@ # metadata -![Version: 0.1.9](https://img.shields.io/badge/Version-0.1.9-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: master](https://img.shields.io/badge/AppVersion-master-informational?style=flat-square) +![Version: 0.1.12](https://img.shields.io/badge/Version-0.1.12-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: master](https://img.shields.io/badge/AppVersion-master-informational?style=flat-square) A Helm chart for gen3 Metadata Service @@ -8,7 +8,7 @@ A Helm chart for gen3 Metadata Service | Repository | Name | Version | |------------|------|---------| -| file://../common | common | 0.1.8 | +| file://../common | common | 0.1.10 | | https://charts.bitnami.com/bitnami | postgresql | 11.9.13 | | https://helm.elastic.co | elasticsearch | 7.17.1 | @@ -46,7 +46,10 @@ A Helm chart for gen3 Metadata Service | elasticsearch.separate | bool | `false` | | | elasticsearch.singleNode | bool | `true` | | | esEndpoint | string | `"http://gen3-elasticsearch-master:9200"` | Elasticsearch endpoint. | -| global | map | `{"aws":{"awsAccessKeyId":null,"awsSecretAccessKey":null,"enabled":false},"ddEnabled":false,"dev":true,"dictionaryUrl":"https://s3.amazonaws.com/dictionary-artifacts/datadictionary/develop/schema.json","dispatcherJobNum":10,"environment":"default","hostname":"localhost","kubeBucket":"kube-gen3","logsBucket":"logs-gen3","minAvialable":1,"netPolicy":true,"pdb":false,"portalApp":"gitops","postgres":{"dbCreate":true,"master":{"host":null,"password":null,"port":"5432","username":"postgres"}},"publicDataSets":true,"revproxyArn":"arn:aws:acm:us-east-1:123456:certificate","tierAccessLevel":"libre"}` | Global configuration options. | +| externalSecrets | map | `{"createK8sMetadataSecret":false,"dbcreds":null,"metadataG3auto":null}` | External Secrets settings. | +| externalSecrets.createK8sMetadataSecret | string | `false` | Will create the Helm "metadata-g3auto" secret even if Secrets Manager is enabled. This is helpful if you are wanting to use External Secrets for some, but not all secrets. | +| externalSecrets.dbcreds | string | `nil` | Will override the name of the aws secrets manager secret. Default is "Values.global.environment-.Chart.Name-creds" | +| externalSecrets.metadataG3auto | string | `nil` | Will override the name of the aws secrets manager secret. Default is "metadata-g3auto" | | global.aws | map | `{"awsAccessKeyId":null,"awsSecretAccessKey":null,"enabled":false}` | AWS configuration | | global.aws.awsAccessKeyId | string | `nil` | Credentials for AWS stuff. | | global.aws.awsSecretAccessKey | string | `nil` | Credentials for AWS stuff. | @@ -54,8 +57,11 @@ A Helm chart for gen3 Metadata Service | global.ddEnabled | bool | `false` | Whether Datadog is enabled. | | global.dev | bool | `true` | Whether the deployment is for development purposes. | | global.dictionaryUrl | string | `"https://s3.amazonaws.com/dictionary-artifacts/datadictionary/develop/schema.json"` | URL of the data dictionary. | -| global.dispatcherJobNum | int | `10` | Number of dispatcher jobs. | +| global.dispatcherJobNum | int | `"10"` | Number of dispatcher jobs. | | global.environment | string | `"default"` | Environment name. This should be the same as vpcname if you're doing an AWS deployment. Currently this is being used to share ALB's if you have multiple namespaces. Might be used other places too. | +| global.externalSecrets | map | `{"deploy":false,"separateSecretStore":false}` | External Secrets settings. | +| global.externalSecrets.deploy | bool | `false` | Will use ExternalSecret resources to pull secrets from Secrets Manager instead of creating them locally. Be cautious as this will override any metadata secrets you have deployed. | +| global.externalSecrets.separateSecretStore | string | `false` | Will deploy a separate External Secret Store for this service. | | global.hostname | string | `"localhost"` | Hostname for the deployment. | | global.kubeBucket | string | `"kube-gen3"` | S3 bucket name for Kubernetes manifest files. | | global.logsBucket | string | `"logs-gen3"` | S3 bucket name for log files. | @@ -63,8 +69,8 @@ A Helm chart for gen3 Metadata Service | global.netPolicy | bool | `true` | Whether network policies are enabled. | | global.pdb | bool | `false` | If the service will be deployed with a Pod Disruption Budget. Note- you need to have more than 2 replicas for the pdb to be deployed. | | global.portalApp | string | `"gitops"` | Portal application name. | -| global.postgres | map | `{"dbCreate":true,"master":{"host":null,"password":null,"port":"5432","username":"postgres"}}` | Postgres database configuration. | | global.postgres.dbCreate | bool | `true` | Whether the database should be created. | +| global.postgres.externalSecret | string | `""` | Name of external secret. Disabled if empty | | global.postgres.master | map | `{"host":null,"password":null,"port":"5432","username":"postgres"}` | Master credentials to postgres. This is going to be the default postgres server being used for each service, unless each service specifies their own postgres | | global.postgres.master.host | string | `nil` | hostname of postgres server | | global.postgres.master.password | string | `nil` | password for superuser in postgres. This is used to create or restore databases | @@ -104,6 +110,9 @@ A Helm chart for gen3 Metadata Service | resources.requests.cpu | string | `0.1` | The amount of CPU requested | | resources.requests.memory | string | `"12Mi"` | The amount of memory requested | | revisionHistoryLimit | int | `2` | Number of old revisions to retain | +| secrets | map | `{"awsAccessKeyId":null,"awsSecretAccessKey":null}` | Secret information to access the db restore job S3 bucket. | +| secrets.awsAccessKeyId | str | `nil` | AWS access key ID. Overrides global key. | +| secrets.awsSecretAccessKey | str | `nil` | AWS secret access key ID. Overrides global key. | | selectorLabels | map | `nil` | Will completely override the selectorLabels defined in the common chart's _label_setup.tpl | | service | map | `{"port":[{"name":"http","port":80,"protocol":"TCP","targetPort":8000}],"type":"ClusterIP"}` | Kubernetes service information. | | service.port | int | `[{"name":"http","port":80,"protocol":"TCP","targetPort":8000}]` | The port number that the service exposes. | @@ -119,5 +128,3 @@ A Helm chart for gen3 Metadata Service | useAggMds | bool | `"True"` | Set to true to aggregate metadata from multiple other Metadata Service instances. | | volumeMounts | list | `[{"mountPath":"/metadata-service/deployment/wsgi/gunicorn.conf.py","name":"wsgi-config","subPath":"gunicorn.conf.py"},{"mountPath":"/src/.env","name":"config-volume-g3auto","readOnly":true,"subPath":"metadata.env"},{"mountPath":"/aggregate_config.json","name":"config-volume","readOnly":true,"subPath":"aggregate_config.json"},{"mountPath":"/metadata.json","name":"config-manifest","readOnly":true,"subPath":"json"}]` | Volumes to mount to the container. | ----------------------------------------------- -Autogenerated from chart metadata using [helm-docs v1.11.0](https://github.com/norwoodj/helm-docs/releases/v1.11.0) diff --git a/helm/metadata/templates/_helpers.tpl b/helm/metadata/templates/_helpers.tpl index f8424983..91c790fd 100644 --- a/helm/metadata/templates/_helpers.tpl +++ b/helm/metadata/templates/_helpers.tpl @@ -77,3 +77,10 @@ Create the name of the service account to use {{- default .Values.postgres.password }} {{- end }} {{- end }} + +{{/* + Metadata g3 Auto Secrets Manager Name +*/}} +{{- define "metadata-g3auto" -}} +{{- default "metadata-g3auto" .Values.externalSecrets.metadataG3auto }} +{{- end }} \ No newline at end of file diff --git a/helm/metadata/templates/aws-config.yaml b/helm/metadata/templates/aws-config.yaml new file mode 100644 index 00000000..4723e6b3 --- /dev/null +++ b/helm/metadata/templates/aws-config.yaml @@ -0,0 +1,3 @@ +{{- if or (.Values.secrets.awsSecretAccessKey) (.Values.global.aws.awsSecretAccessKey ) }} +{{ include "common.awsconfig" . }} +{{- end }} \ No newline at end of file diff --git a/helm/metadata/templates/external-secret.yaml b/helm/metadata/templates/external-secret.yaml new file mode 100644 index 00000000..c3bb3465 --- /dev/null +++ b/helm/metadata/templates/external-secret.yaml @@ -0,0 +1,32 @@ +{{ if .Values.global.externalSecrets.deploy }} +apiVersion: external-secrets.io/v1beta1 +kind: ExternalSecret +metadata: + name: metadata-g3auto +spec: + refreshInterval: 5m + secretStoreRef: + name: {{include "common.SecretStore" .}} + kind: SecretStore + target: + name: metadata-g3auto + creationPolicy: Owner + data: + - secretKey: base64Authz.txt + remoteRef: + #name of secret in secrets manager + key: {{include "metadata-g3auto" .}} + property: base64Authz.txt + - secretKey: dbcreds.json + remoteRef: + #name of secret in secrets manager + key: {{include "metadata-g3auto" .}} + property: dbcreds.json + - secretKey: metadata.env + remoteRef: + #name of secret in secrets manager + key: {{include "metadata-g3auto" .}} + property: metadata.env +{{- end }} +--- +{{ include "common.externalSecret.db" . }} \ No newline at end of file diff --git a/helm/metadata/templates/secret-store.yaml b/helm/metadata/templates/secret-store.yaml new file mode 100644 index 00000000..771c7760 --- /dev/null +++ b/helm/metadata/templates/secret-store.yaml @@ -0,0 +1,3 @@ +{{ if .Values.global.externalSecrets.separateSecretStore }} +{{ include "common.secretstore" . }} +{{- end }} \ No newline at end of file diff --git a/helm/metadata/templates/secrets.yaml b/helm/metadata/templates/secrets.yaml index fcde0e48..0bd639d7 100644 --- a/helm/metadata/templates/secrets.yaml +++ b/helm/metadata/templates/secrets.yaml @@ -1,21 +1,16 @@ +{{- if or (not .Values.global.externalSecrets.deploy) (and .Values.global.externalSecrets.deploy .Values.externalSecrets.createK8sMetadataSecret) }} apiVersion: v1 kind: Secret metadata: name: metadata-g3auto stringData: {{- $randomPass := printf "%s%s" "gateway:" (randAlphaNum 32) }} - base64Authz.txt: {{ $randomPass | b64enc | quote }} - dbcreds.json: | - { - "db_host": {{ .Values.postgres.host | quote }}, - "db_username": {{ .Values.postgres.user | quote}}, - "db_password": {{ include "metadata.postgres.password" . | quote }}, - "db_database": {{ .Values.postgres.dbname | quote }} - } + base64Authz.txt: {{ $randomPass | quote | b64enc }} metadata.env: | DEBUG={{ .Values.debug}} DB_HOST={{ .Values.postgres.host }} DB_USER={{ .Values.postgres.user }} DB_PASSWORD={{ include "metadata.postgres.password" . }} DB_DATABASE={{ .Values.postgres.dbname }} - ADMIN_LOGINS={{ $randomPass }} \ No newline at end of file + ADMIN_LOGINS={{ $randomPass }} +{{- end }} \ No newline at end of file diff --git a/helm/metadata/values.yaml b/helm/metadata/values.yaml index 9736b621..abf55d69 100644 --- a/helm/metadata/values.yaml +++ b/helm/metadata/values.yaml @@ -2,7 +2,8 @@ # This is a YAML-formatted file. # Declare variables to be passed into your templates. -# -- (map) Global configuration options. + +# Global configuration global: # -- (map) AWS configuration aws: @@ -14,10 +15,12 @@ global: awsSecretAccessKey: # -- (bool) Whether the deployment is for development purposes. dev: true - # -- (map) Postgres database configuration. + postgres: # -- (bool) Whether the database should be created. dbCreate: true + # -- (string) Name of external secret. Disabled if empty + externalSecret: "" # -- (map) Master credentials to postgres. This is going to be the default postgres server being used for each service, unless each service specifies their own postgres master: # -- (string) hostname of postgres server @@ -49,13 +52,34 @@ global: # -- (bool) Whether network policies are enabled. netPolicy: true # -- (int) Number of dispatcher jobs. - dispatcherJobNum: 10 + dispatcherJobNum: "10" # -- (bool) Whether Datadog is enabled. ddEnabled: false # -- (bool) If the service will be deployed with a Pod Disruption Budget. Note- you need to have more than 2 replicas for the pdb to be deployed. pdb: false # -- (int) The minimum amount of pods that are available at all times if the PDB is deployed. minAvialable: 1 + # -- (map) External Secrets settings. + externalSecrets: + # -- (bool) Will use ExternalSecret resources to pull secrets from Secrets Manager instead of creating them locally. Be cautious as this will override any metadata secrets you have deployed. + deploy: false + # -- (string) Will deploy a separate External Secret Store for this service. + separateSecretStore: false + +# -- (map) External Secrets settings. +externalSecrets: + # -- (string) Will create the Helm "metadata-g3auto" secret even if Secrets Manager is enabled. This is helpful if you are wanting to use External Secrets for some, but not all secrets. + createK8sMetadataSecret: false + # -- (string) Will override the name of the aws secrets manager secret. Default is "metadata-g3auto" + metadataG3auto: + # -- (string) Will override the name of the aws secrets manager secret. Default is "Values.global.environment-.Chart.Name-creds" + dbcreds: +# -- (map) Secret information to access the db restore job S3 bucket. +secrets: + # -- (str) AWS access key ID. Overrides global key. + awsAccessKeyId: + # -- (str) AWS secret access key ID. Overrides global key. + awsSecretAccessKey: # -- (map) Postgres database configuration. If db does not exist in postgres cluster and dbCreate is set ot true then these databases will be created for you postgres: diff --git a/helm/neuvector/.helmignore b/helm/neuvector/.helmignore new file mode 100644 index 00000000..0e8a0eb3 --- /dev/null +++ b/helm/neuvector/.helmignore @@ -0,0 +1,23 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*.orig +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ diff --git a/helm/neuvector/Chart.yaml b/helm/neuvector/Chart.yaml new file mode 100644 index 00000000..46be470b --- /dev/null +++ b/helm/neuvector/Chart.yaml @@ -0,0 +1,34 @@ +apiVersion: v2 +name: neuvector +description: NeuVector Kubernetes Security Policy templates to protect Gen3 + +# NeuVector must be installed separately. +# Reference: https://open-docs.neuvector.com/basics/overview +# Reference: https://github.com/neuvector/neuvector-helm +# For more information, please use the Gen3 community Slack. +# A chart can be either an 'application' or a 'library' chart. +# +# Application charts are a collection of templates that can be packaged into versioned archives +# to be deployed. +# +# Library charts provide useful utilities or functions for the chart developer. They're included as +# a dependency of application charts to inject those utilities and functions into the rendering +# pipeline. Library charts do not define any templates and therefore cannot be deployed. +type: application + +# This is the chart version. This version number should be incremented each time you make changes +# to the chart and its templates, including the app version. +# Versions are expected to follow Semantic Versioning (https://semver.org/) +version: 0.1.0 + +# This is the version number of the application being deployed. This version number should be +# incremented each time you make changes to the application. Versions are not expected to +# follow Semantic Versioning. They should reflect the version the application is using. +# It is recommended to use it with quotes. +appVersion: "1.16.0" + +# Todo: Evaluate inclusion of NeuVector installation +# dependencies: +# - name: neuvector +# version: "5.2.2-s1" +# repository: "https://neuvector.github.io/neuvector-helm/core" diff --git a/helm/neuvector/README.md b/helm/neuvector/README.md new file mode 100644 index 00000000..c69d8513 --- /dev/null +++ b/helm/neuvector/README.md @@ -0,0 +1,21 @@ +# neuvector + +![Version: 0.1.0](https://img.shields.io/badge/Version-0.1.0-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: 1.16.0](https://img.shields.io/badge/AppVersion-1.16.0-informational?style=flat-square) + +NeuVector Kubernetes Security Policy templates to protect Gen3 + +## Values + +| Key | Type | Default | Description | +|-----|------|---------|-------------| +| ARGOCD_PREFIX | string | `"development-gen3"` | | +| DB_HOST | string | `"development-gen3-postgresql"` | | +| ES_HOST | string | `"gen3-elasticsearch-master"` | | +| fullnameOverride | string | `""` | | +| ingress.class | string | `"nginx"` | | +| ingress.controller | string | `"nginx-ingress-controller"` | | +| ingress.namespace | string | `"nginx"` | | +| nameOverride | string | `""` | | +| policies.include | bool | `true` | | +| policies.policyMode | string | `"Monitor"` | | + diff --git a/helm/neuvector/templates/_helpers.tpl b/helm/neuvector/templates/_helpers.tpl new file mode 100644 index 00000000..cc8472e7 --- /dev/null +++ b/helm/neuvector/templates/_helpers.tpl @@ -0,0 +1,62 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "neuvector.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 "neuvector.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 "neuvector.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "neuvector.labels" -}} +helm.sh/chart: {{ include "neuvector.chart" . }} +{{ include "neuvector.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "neuvector.selectorLabels" -}} +app.kubernetes.io/name: {{ include "neuvector.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} + +{{/* +Create the name of the service account to use +*/}} +{{- define "neuvector.serviceAccountName" -}} +{{- if .Values.serviceAccount.create }} +{{- default (include "neuvector.fullname" .) .Values.serviceAccount.name }} +{{- else }} +{{- default "default" .Values.serviceAccount.name }} +{{- end }} +{{- end }} diff --git a/helm/neuvector/templates/ambassador-nvsecurityrule.yaml b/helm/neuvector/templates/ambassador-nvsecurityrule.yaml new file mode 100644 index 00000000..01166345 --- /dev/null +++ b/helm/neuvector/templates/ambassador-nvsecurityrule.yaml @@ -0,0 +1,212 @@ +{{- if .Values.policies.include }} +apiVersion: neuvector.com/v1 +kind: NvSecurityRule +metadata: + name: nv.ambassador-deployment.{{ .Release.Namespace }} +spec: + dlp: + settings: [] + status: true + egress: + - action: allow + applications: + - DNS + name: nv.kube-dns.kube-system-egress-0 + ports: any + priority: 0 + selector: + comment: "" + criteria: + - key: service + op: = + value: kube-dns.kube-system + - key: domain + op: = + value: kube-system + name: nv.kube-dns.kube-system + original_name: "" + - action: allow + applications: + - SSL + name: external-egress-1 + ports: any + priority: 0 + selector: + comment: "" + criteria: [] + name: external + original_name: "" + file: [] + ingress: + - action: allow + applications: + - HTTP + name: nv.ambassador-deployment.{{ .Release.Namespace }}-ingress-6 + ports: any + priority: 0 + selector: + comment: "" + name: Workload:ingress + original_name: "" + - action: allow + applications: + - SSL + name: nv.ambassador-deployment.{{ .Release.Namespace }}-ingress-7 + ports: any + priority: 0 + selector: + comment: "" + criteria: + - key: service + op: = + value: hatchery-deployment.{{ .Release.Namespace }} + - key: domain + op: = + value: {{ .Release.Namespace }} + name: nv.hatchery-deployment.{{ .Release.Namespace }} + original_name: "" + - action: allow + applications: + - SSL + name: nv.ambassador-deployment.{{ .Release.Namespace }}-ingress-8 + ports: any + priority: 0 + selector: + comment: "" + criteria: [] + name: external + original_name: "" + - action: allow + applications: + - HTTP + name: nv.ambassador-deployment.{{ .Release.Namespace }}-ingress-9 + ports: any + priority: 0 + selector: + comment: "" + criteria: + - key: service + op: = + value: revproxy-deployment.{{ .Release.Namespace }} + - key: domain + op: = + value: {{ .Release.Namespace }} + name: nv.revproxy-deployment.{{ .Release.Namespace }} + original_name: "" + - action: allow + applications: + - any + name: nv.ambassador-deployment.{{ .Release.Namespace }}-ingress-10 + ports: tcp/8080 + priority: 0 + selector: + comment: "" + criteria: + - key: service + op: = + value: revproxy-deployment.{{ .Release.Namespace }} + - key: domain + op: = + value: {{ .Release.Namespace }} + name: nv.revproxy-deployment.{{ .Release.Namespace }} + original_name: "" + process: + - action: allow + allow_update: false + name: ambex + path: /opt/ambassador/bin/ambassador + - action: allow + allow_update: false + name: bash + path: /bin/bash + - action: allow + allow_update: false + name: busybox + path: /bin/busybox + - action: allow + allow_update: false + name: curl + path: /usr/bin/curl + - action: allow + allow_update: false + name: date + path: /bin/busybox + - action: allow + allow_update: false + name: diagd + path: /usr/bin/python3.7 + - action: allow + allow_update: false + name: env + path: /bin/busybox + - action: allow + allow_update: false + name: envoy + path: /usr/local/bin/envoy + - action: allow + allow_update: false + name: find + path: /bin/busybox + - action: allow + allow_update: false + name: grep + path: /bin/busybox + - action: allow + allow_update: false + name: mkdir + path: /bin/busybox + - action: allow + allow_update: false + name: pause + path: /pause + - action: allow + allow_update: false + name: python + path: /usr/bin/python3.7 + - action: allow + allow_update: false + name: python3 + path: /usr/bin/python3.7 + - action: allow + allow_update: false + name: sh + path: /bin/busybox + - action: allow + allow_update: false + name: sleep + path: /bin/busybox + - action: allow + allow_update: false + name: sort + path: /bin/busybox + - action: allow + allow_update: false + name: uname + path: /bin/busybox + - action: allow + allow_update: false + name: watt + path: /opt/ambassador/bin/ambassador + - action: allow + allow_update: false + name: wc + path: /bin/busybox + process_profile: + baseline: zero-drift + target: + policymode: {{ .Values.policies.policyMode }} + selector: + comment: "" + criteria: + - key: service + op: = + value: ambassador-deployment.{{ .Release.Namespace }} + - key: domain + op: = + value: {{ .Release.Namespace }} + name: nv.ambassador-deployment.{{ .Release.Namespace }} + original_name: "" + waf: + settings: [] + status: true +{{- end }} \ No newline at end of file diff --git a/helm/neuvector/templates/arborist-nvsecurityrule.yaml b/helm/neuvector/templates/arborist-nvsecurityrule.yaml new file mode 100644 index 00000000..5ee722d7 --- /dev/null +++ b/helm/neuvector/templates/arborist-nvsecurityrule.yaml @@ -0,0 +1,218 @@ +{{- if .Values.policies.include }} +apiVersion: neuvector.com/v1 +kind: NvSecurityRule +metadata: + name: nv.arborist-deployment.{{ .Release.Namespace }} +spec: + dlp: + settings: [] + status: true + egress: + - action: allow + applications: + - DNS + name: nv.kube-dns.kube-system-egress-7 + ports: any + priority: 0 + selector: + comment: "" + criteria: + - key: service + op: = + value: kube-dns.kube-system + - key: domain + op: = + value: kube-system + name: nv.kube-dns.kube-system + original_name: "" + - action: allow + applications: + - HTTP + name: nv.fence-deployment.{{ .Release.Namespace }}-egress-8 + ports: any + priority: 0 + selector: + comment: "" + criteria: + - key: service + op: = + value: fence-deployment.{{ .Release.Namespace }} + - key: domain + op: = + value: {{ .Release.Namespace }} + name: nv.fence-deployment.{{ .Release.Namespace }} + original_name: "" + - action: allow + applications: + - PostgreSQL + name: nv.{{ .Values.DB_HOST }}.{{ .Release.Namespace }}-egress-9 + ports: any + priority: 0 + selector: + comment: "" + criteria: + - key: service + op: = + value: {{ .Values.DB_HOST }}.{{ .Release.Namespace }} + - key: domain + op: = + value: {{ .Release.Namespace }} + name: nv.{{ .Values.DB_HOST }}.{{ .Release.Namespace }} + original_name: "" + file: [] + ingress: + - action: allow + applications: + - HTTP + name: nv.arborist-deployment.{{ .Release.Namespace }}-ingress-17 + ports: any + priority: 0 + selector: + comment: "" + name: Workload:ingress + original_name: "" + - action: allow + applications: + - HTTP + name: nv.arborist-deployment.{{ .Release.Namespace }}-ingress-18 + ports: any + priority: 0 + selector: + comment: "" + criteria: + - key: service + op: = + value: revproxy-deployment.{{ .Release.Namespace }} + - key: domain + op: = + value: {{ .Release.Namespace }} + name: nv.revproxy-deployment.{{ .Release.Namespace }} + original_name: "" + - action: allow + applications: + - SSL + name: nv.arborist-deployment.{{ .Release.Namespace }}-ingress-19 + ports: any + priority: 0 + selector: + comment: "" + criteria: [] + name: external + original_name: "" + - action: allow + applications: + - HTTP + name: nv.arborist-deployment.{{ .Release.Namespace }}-ingress-20 + ports: any + priority: 0 + selector: + comment: "" + criteria: + - key: service + op: = + value: fence-deployment.{{ .Release.Namespace }} + - key: domain + op: = + value: {{ .Release.Namespace }} + name: nv.fence-deployment.{{ .Release.Namespace }} + original_name: "" + - action: allow + applications: + - HTTP + name: nv.arborist-deployment.{{ .Release.Namespace }}-ingress-21 + ports: any + priority: 0 + selector: + comment: "" + criteria: + - key: service + op: = + value: peregrine-deployment.{{ .Release.Namespace }} + - key: domain + op: = + value: {{ .Release.Namespace }} + name: nv.peregrine-deployment.{{ .Release.Namespace }} + original_name: "" + - action: allow + applications: + - HTTP + name: nv.arborist-deployment.{{ .Release.Namespace }}-ingress-22 + ports: any + priority: 0 + selector: + comment: "" + criteria: + - key: service + op: = + value: guppy-deployment.{{ .Release.Namespace }} + - key: domain + op: = + value: {{ .Release.Namespace }} + name: nv.guppy-deployment.{{ .Release.Namespace }} + original_name: "" + - action: allow + applications: + - HTTP + name: nv.arborist-deployment.{{ .Release.Namespace }}-ingress-23 + ports: any + priority: 0 + selector: + comment: "" + criteria: + - key: service + op: = + value: sheepdog-deployment.{{ .Release.Namespace }} + - key: domain + op: = + value: {{ .Release.Namespace }} + name: nv.sheepdog-deployment.{{ .Release.Namespace }} + original_name: "" + - action: allow + applications: + - SSL + name: nv.arborist-deployment.{{ .Release.Namespace }}-ingress-24 + ports: any + priority: 0 + selector: + comment: "" + criteria: + - key: service + op: = + value: hatchery-deployment.{{ .Release.Namespace }} + - key: domain + op: = + value: {{ .Release.Namespace }} + name: nv.hatchery-deployment.{{ .Release.Namespace }} + original_name: "" + process: + - action: allow + allow_update: false + name: arborist + path: /go/src/github.com/uc-cdis/arborist/bin/arborist + - action: allow + allow_update: false + name: pause + path: /pause + - action: allow + allow_update: false + name: sh + path: /bin/dash + process_profile: + baseline: zero-drift + target: + policymode: {{ .Values.policies.policyMode }} + selector: + comment: "" + criteria: + - key: service + op: = + value: arborist-deployment.{{ .Release.Namespace }} + - key: domain + op: = + value: {{ .Release.Namespace }} + name: nv.arborist-deployment.{{ .Release.Namespace }} + original_name: "" + waf: + settings: [] + status: true +{{- end }} \ No newline at end of file diff --git a/helm/neuvector/templates/audit-nvsecurityrule.yaml b/helm/neuvector/templates/audit-nvsecurityrule.yaml new file mode 100644 index 00000000..5320e394 --- /dev/null +++ b/helm/neuvector/templates/audit-nvsecurityrule.yaml @@ -0,0 +1,98 @@ +{{- if .Values.policies.include }} +apiVersion: neuvector.com/v1 +kind: NvSecurityRule +metadata: + name: nv.audit-deployment.{{ .Release.Namespace }} +spec: + dlp: + settings: [] + status: true + egress: + - action: allow + applications: + - DNS + name: nv.kube-dns.kube-system-egress-5 + ports: any + priority: 0 + selector: + comment: "" + criteria: + - key: service + op: = + value: kube-dns.kube-system + - key: domain + op: = + value: kube-system + name: nv.kube-dns.kube-system + original_name: "" + - action: allow + applications: + - PostgreSQL + name: nv.{{ .Values.DB_HOST }}.{{ .Release.Namespace }}-egress-6 + ports: any + priority: 0 + selector: + comment: "" + criteria: + - key: service + op: = + value: {{ .Values.DB_HOST }}.{{ .Release.Namespace }} + - key: domain + op: = + value: {{ .Release.Namespace }} + name: nv.{{ .Values.DB_HOST }}.{{ .Release.Namespace }} + original_name: "" + file: [] + ingress: + - action: allow + applications: + - HTTP + name: nv.audit-deployment.{{ .Release.Namespace }}-ingress-15 + ports: any + priority: 0 + selector: + comment: "" + name: Workload:ingress + original_name: "" + - action: allow + applications: + - any + name: nv.audit-deployment.{{ .Release.Namespace }}-ingress-16 + ports: tcp/80 + priority: 0 + selector: + comment: "" + name: Workload:ingress + original_name: "" + process: + - action: allow + allow_update: false + name: alembic + path: /usr/local/bin/python3.9 + - action: allow + allow_update: false + name: gunicorn + path: /usr/local/bin/python3.9 + - action: allow + allow_update: false + name: pause + path: /pause + process_profile: + baseline: zero-drift + target: + policymode: {{ .Values.policies.policyMode }} + selector: + comment: "" + criteria: + - key: service + op: = + value: audit-deployment.{{ .Release.Namespace }} + - key: domain + op: = + value: {{ .Release.Namespace }} + name: nv.audit-deployment.{{ .Release.Namespace }} + original_name: "" + waf: + settings: [] + status: true +{{- end }} \ No newline at end of file diff --git a/helm/neuvector/templates/elasticsearch-nvsecurityrule.yaml b/helm/neuvector/templates/elasticsearch-nvsecurityrule.yaml new file mode 100644 index 00000000..4089bf63 --- /dev/null +++ b/helm/neuvector/templates/elasticsearch-nvsecurityrule.yaml @@ -0,0 +1,87 @@ +{{- if .Values.policies.include }} +apiVersion: neuvector.com/v1 +kind: NvSecurityRule +metadata: + name: nv.gen3-elasticsearch-master.{{ .Release.Namespace }} +spec: + dlp: + settings: [] + status: true + egress: [] + file: [] + ingress: + - action: allow + applications: + - any + name: nv.gen3-elasticsearch-master.{{ .Release.Namespace }}-ingress-39 + ports: tcp/9200 + priority: 0 + selector: + comment: "" + criteria: + - key: service + op: = + value: revproxy-deployment.{{ .Release.Namespace }} + - key: domain + op: = + value: {{ .Release.Namespace }} + name: nv.revproxy-deployment.{{ .Release.Namespace }} + original_name: "" + - action: allow + applications: + - any + name: nv.gen3-elasticsearch-master.{{ .Release.Namespace }}-ingress-40 + ports: tcp/9200 + priority: 0 + selector: + comment: "" + criteria: + - key: service + op: = + value: guppy-deployment.{{ .Release.Namespace }} + - key: domain + op: = + value: {{ .Release.Namespace }} + name: nv.guppy-deployment.{{ .Release.Namespace }} + original_name: "" + - action: allow + applications: + - any + name: nv.gen3-elasticsearch-master.{{ .Release.Namespace }}-ingress-41 + ports: tcp/9200 + priority: 0 + selector: + comment: "" + criteria: + - key: service + op: = + value: guppy-deployment.{{ .Release.Namespace }} + - key: domain + op: = + value: {{ .Release.Namespace }} + name: nv.guppy-deployment.{{ .Release.Namespace }} + original_name: "" + process: + - action: allow + allow_update: false + name: sh + path: '*' + process_profile: + baseline: zero-drift + target: + policymode: {{ .Values.policies.policyMode }} + selector: + comment: "" + criteria: + - key: service + op: = + value: gen3-elasticsearch-master.{{ .Release.Namespace }} + - key: domain + op: = + value: {{ .Release.Namespace }} + name: nv.gen3-elasticsearch-master.{{ .Release.Namespace }} + original_name: "" + waf: + settings: [] + status: true +{{- end }} \ No newline at end of file diff --git a/helm/neuvector/templates/etl-cronjob-nvsecurityrule.yaml b/helm/neuvector/templates/etl-cronjob-nvsecurityrule.yaml new file mode 100644 index 00000000..8a75b418 --- /dev/null +++ b/helm/neuvector/templates/etl-cronjob-nvsecurityrule.yaml @@ -0,0 +1,346 @@ +apiVersion: neuvector.com/v1 +kind: NvSecurityRule +metadata: + name: nv.etl-cronjob-rule.{{ .Release.Namespace }} +spec: + dlp: + settings: [] + status: true + egress: + - action: allow + applications: + - DNS + name: nv.kube-dns.kube-system-egress-0 + ports: any + priority: 0 + selector: + comment: "" + criteria: + - key: service + op: = + value: kube-dns.kube-system + - key: domain + op: = + value: kube-system + name: nv.kube-dns.kube-system + original_name: "" + - action: allow + applications: + - HTTP + name: nv.{{ .Values.ES_HOST }}.{{ .Release.Namespace }}-egress-1 + ports: any + priority: 0 + selector: + comment: "" + criteria: + - key: service + op: = + value: {{ .Values.ES_HOST }}.{{ .Release.Namespace }} + - key: domain + op: = + value: {{ .Release.Namespace }} + name: nv.{{ .Values.ES_HOST }}.{{ .Release.Namespace }} + original_name: "" + - action: allow + applications: + - PostgreSQL + name: nv.{{ .Values.DB_HOST }}.{{ .Release.Namespace }}-egress-2 + ports: any + priority: 0 + selector: + comment: "" + criteria: + - key: service + op: = + value: {{ .Values.DB_HOST }}.{{ .Release.Namespace }} + - key: domain + op: = + value: {{ .Release.Namespace }} + name: nv.{{ .Values.DB_HOST }}.{{ .Release.Namespace }} + original_name: "" + - action: allow + applications: + - SSL + name: external-egress-3 + ports: any + priority: 0 + selector: + comment: "" + criteria: [] + name: external + original_name: "" + - action: allow + applications: + - HTTP + name: nv.revproxy-deployment.{{ .Release.Namespace }}-egress-4 + ports: any + priority: 0 + selector: + comment: "" + criteria: + - key: service + op: = + value: revproxy-deployment.{{ .Release.Namespace }} + - key: domain + op: = + value: {{ .Release.Namespace }} + name: nv.revproxy-deployment.{{ .Release.Namespace }} + original_name: "" + file: [] + ingress: + - action: allow + applications: + - any + name: nv.etl-cronjob.{{ .Release.Namespace }}-ingress-0 + ports: tcp/9000 + priority: 0 + selector: + comment: "" + name: Workload:ingress + original_name: "" + process: + - action: allow + allow_update: false + name: basename + path: /usr/bin/basename + - action: allow + allow_update: false + name: bash + path: /bin/bash + - action: allow + allow_update: false + name: bash + path: /usr/bin/env + - action: allow + allow_update: false + name: bash + path: /usr/bin/setsid + - action: allow + allow_update: false + name: cat + path: /bin/cat + - action: allow + allow_update: false + name: chmod + path: /bin/chmod + - action: allow + allow_update: false + name: cp + path: /bin/cp + - action: allow + allow_update: false + name: df + path: /bin/df + - action: allow + allow_update: false + name: dirname + path: /usr/bin/dirname + - action: allow + allow_update: false + name: dpkg + path: /usr/bin/dpkg + - action: allow + allow_update: false + name: dpkg-query + path: /usr/bin/dpkg-query + - action: allow + allow_update: false + name: du + path: /usr/bin/du + - action: allow + allow_update: false + name: env + path: /usr/bin/env + - action: allow + allow_update: false + name: getconf + path: /usr/bin/getconf + - action: allow + allow_update: false + name: gzip + path: /bin/gzip + - action: allow + allow_update: false + name: hadoop + path: /usr/bin/env + - action: allow + allow_update: false + name: hdfs + path: /usr/bin/env + - action: allow + allow_update: false + name: head + path: /usr/bin/head + - action: allow + allow_update: false + name: id + path: /usr/bin/id + - action: allow + allow_update: false + name: java + path: /usr/lib/jvm/java-11-openjdk-amd64/bin/java + - action: allow + allow_update: false + name: jks-keystore + path: /bin/dash + - action: allow + allow_update: false + name: ld-2.28.so + path: /lib/x86_64-linux-gnu/ld-2.28.so + - action: allow + allow_update: false + name: ld-linux-x86-64 + path: /lib/x86_64-linux-gnu/ld-2.28.so + - action: allow + allow_update: false + name: ld-linux-x86-64.so.2 + path: /lib/x86_64-linux-gnu/ld-2.28.so + - action: allow + allow_update: false + name: ldd + path: /bin/bash + - action: allow + allow_update: false + name: ls + path: /bin/ls + - action: allow + allow_update: false + name: mkdir + path: /bin/mkdir + - action: allow + allow_update: false + name: mountpoint + path: /bin/mountpoint + - action: allow + allow_update: false + name: mv + path: /bin/mv + - action: allow + allow_update: false + name: nice + path: /usr/bin/nice + - action: allow + allow_update: false + name: nohup + path: /usr/bin/nohup + - action: allow + allow_update: false + name: pause + path: /pause + - action: allow + allow_update: false + name: ps + path: /bin/ps + - action: allow + allow_update: false + name: psql + path: /usr/bin/perl + - action: allow + allow_update: false + name: psql + path: /usr/lib/postgresql/11/bin/psql + - action: allow + allow_update: false + name: python + path: /usr/local/bin/python3.9 + - action: allow + allow_update: false + name: python3 + path: /usr/local/bin/python3.9 + - action: allow + allow_update: false + name: readlink + path: /bin/readlink + - action: allow + allow_update: false + name: renice + path: /usr/bin/renice + - action: allow + allow_update: false + name: rm + path: /bin/rm + - action: allow + allow_update: false + name: sed + path: /bin/sed + - action: allow + allow_update: false + name: setsid + path: /usr/bin/setsid + - action: allow + allow_update: false + name: sh + path: /bin/dash + - action: allow + allow_update: false + name: slaves.sh + path: /usr/bin/env + - action: allow + allow_update: false + name: sleep + path: /bin/sleep + - action: allow + allow_update: false + name: spark-class + path: /usr/bin/env + - action: allow + allow_update: false + name: spark-submit + path: /usr/bin/env + - action: allow + allow_update: false + name: sqoop + path: /bin/bash + - action: allow + allow_update: false + name: ssh-keygen + path: /usr/bin/ssh-keygen + - action: allow + allow_update: false + name: sysctl + path: /sbin/sysctl + - action: allow + allow_update: false + name: tail + path: /usr/bin/tail + - action: allow + allow_update: false + name: tar + path: /bin/tar + - action: allow + allow_update: false + name: touch + path: /bin/touch + - action: allow + allow_update: false + name: tr + path: /usr/bin/tr + - action: allow + allow_update: false + name: uname + path: /bin/uname + - action: allow + allow_update: false + name: wget + path: /usr/bin/wget + - action: allow + allow_update: false + name: yarn + path: /usr/bin/env + process_profile: + baseline: zero-drift + target: + selector: + comment: "" + criteria: + - key: service + op: regex + value: etl-cronjob-.*\.{{ .Release.Namespace }} + - key: domain + op: = + value: {{ .Release.Namespace }} + name: etl-cronjob.{{ .Release.Namespace }} + original_name: "" + waf: + settings: [] + status: true diff --git a/helm/neuvector/templates/fence-nvsecurityrule.yaml b/helm/neuvector/templates/fence-nvsecurityrule.yaml new file mode 100644 index 00000000..8dc08b8f --- /dev/null +++ b/helm/neuvector/templates/fence-nvsecurityrule.yaml @@ -0,0 +1,294 @@ +{{- if .Values.policies.include }} +apiVersion: neuvector.com/v1 +kind: NvSecurityRule +metadata: + name: nv.fence-deployment.{{ .Release.Namespace }} +spec: + dlp: + settings: [] + status: true + egress: + - action: allow + applications: + - any + name: nodes-egress-12 + ports: tcp/8126 + priority: 0 + selector: + comment: "" + criteria: [] + name: nodes + original_name: "" + - action: allow + applications: + - DNS + name: nv.kube-dns.kube-system-egress-13 + ports: any + priority: 0 + selector: + comment: "" + criteria: + - key: service + op: = + value: kube-dns.kube-system + - key: domain + op: = + value: kube-system + name: nv.kube-dns.kube-system + original_name: "" + - action: allow + applications: + - SSL + name: external-egress-14 + ports: any + priority: 0 + selector: + comment: "" + criteria: [] + name: external + original_name: "" + file: [] + ingress: + - action: allow + applications: + - HTTP + name: nv.fence-deployment.{{ .Release.Namespace }}-ingress-31 + ports: any + priority: 0 + selector: + comment: "" + name: Workload:ingress + original_name: "" + - action: allow + applications: + - SSL + name: nv.fence-deployment.{{ .Release.Namespace }}-ingress-32 + ports: any + priority: 0 + selector: + comment: "" + criteria: [] + name: external + original_name: "" + - action: allow + applications: + - HTTP + name: nv.fence-deployment.{{ .Release.Namespace }}-ingress-33 + ports: any + priority: 0 + selector: + comment: "" + criteria: + - key: service + op: = + value: revproxy-deployment.{{ .Release.Namespace }} + - key: domain + op: = + value: {{ .Release.Namespace }} + name: nv.revproxy-deployment.{{ .Release.Namespace }} + original_name: "" + - action: allow + applications: + - SSL + name: nv.fence-deployment.{{ .Release.Namespace }}-ingress-34 + ports: any + priority: 0 + selector: + comment: "" + criteria: + - key: service + op: = + value: peregrine-deployment.{{ .Release.Namespace }} + - key: domain + op: = + value: {{ .Release.Namespace }} + name: nv.peregrine-deployment.{{ .Release.Namespace }} + original_name: "" + - action: allow + applications: + - SSL + name: nv.fence-deployment.{{ .Release.Namespace }}-ingress-35 + ports: any + priority: 0 + selector: + comment: "" + criteria: + - key: service + op: = + value: hatchery-deployment.{{ .Release.Namespace }} + - key: domain + op: = + value: {{ .Release.Namespace }} + name: nv.hatchery-deployment.{{ .Release.Namespace }} + original_name: "" + - action: allow + applications: + - SSL + name: nv.fence-deployment.{{ .Release.Namespace }}-ingress-36 + ports: any + priority: 0 + selector: + comment: "" + criteria: + - key: service + op: = + value: sheepdog-deployment.{{ .Release.Namespace }} + - key: domain + op: = + value: {{ .Release.Namespace }} + name: nv.sheepdog-deployment.{{ .Release.Namespace }} + original_name: "" + - action: allow + applications: + - SSL + name: nv.fence-deployment.{{ .Release.Namespace }}-ingress-37 + ports: any + priority: 0 + selector: + comment: "" + criteria: + - key: service + op: = + value: cert-manager.cert-manager + - key: domain + op: = + value: cert-manager + name: nv.cert-manager.cert-manager + original_name: "" + - action: allow + applications: + - HTTP + name: nv.fence-deployment.{{ .Release.Namespace }}-ingress-38 + ports: any + priority: 0 + selector: + comment: "" + criteria: + - key: service + op: = + value: manifestservice-deployment.{{ .Release.Namespace }} + - key: domain + op: = + value: {{ .Release.Namespace }} + name: nv.manifestservice-deployment.{{ .Release.Namespace }} + original_name: "" + process: + - action: allow + allow_update: false + name: basename + path: /usr/bin/basename + - action: allow + allow_update: false + name: bash + path: /bin/bash + - action: allow + allow_update: false + name: cat + path: /bin/cat + - action: allow + allow_update: false + name: chmod + path: /bin/chmod + - action: allow + allow_update: false + name: chown + path: /bin/chown + - action: allow + allow_update: false + name: ddtrace-run + path: /usr/local/bin/python3.9 + - action: allow + allow_update: false + name: fence-create + path: /usr/local/bin/python3.9 + - action: allow + allow_update: false + name: find + path: /usr/bin/find + - action: allow + allow_update: false + name: ldconfig + path: /sbin/ldconfig + - action: allow + allow_update: false + name: ls + path: /bin/ls + - action: allow + allow_update: false + name: mkdir + path: /bin/mkdir + - action: allow + allow_update: false + name: mv + path: /bin/mv + - action: allow + allow_update: false + name: nginx + path: /usr/sbin/nginx + - action: allow + allow_update: false + name: pause + path: /pause + - action: allow + allow_update: false + name: pip + path: /usr/local/bin/python3.9 + - action: allow + allow_update: false + name: python + path: /usr/local/bin/python3.9 + - action: allow + allow_update: false + name: readlink + path: /bin/readlink + - action: allow + allow_update: false + name: rm + path: /bin/rm + - action: allow + allow_update: false + name: run-parts + path: /bin/run-parts + - action: allow + allow_update: false + name: sed + path: /bin/sed + - action: allow + allow_update: false + name: sh + path: /bin/dash + - action: allow + allow_update: false + name: sort + path: /usr/bin/sort + - action: allow + allow_update: false + name: uname + path: /bin/uname + - action: allow + allow_update: false + name: uwsgi + path: /usr/local/bin/uwsgi + - action: allow + allow_update: false + name: wc + path: /usr/bin/wc + process_profile: + baseline: zero-drift + target: + policymode: {{ .Values.policies.policyMode }} + selector: + comment: "" + criteria: + - key: service + op: = + value: fence-deployment.{{ .Release.Namespace }} + - key: domain + op: = + value: {{ .Release.Namespace }} + name: nv.fence-deployment.{{ .Release.Namespace }} + original_name: "" + waf: + settings: [] + status: true +{{- end }} \ No newline at end of file diff --git a/helm/neuvector/templates/guppy-nvsecurityrule.yaml b/helm/neuvector/templates/guppy-nvsecurityrule.yaml new file mode 100644 index 00000000..6d05c7fd --- /dev/null +++ b/helm/neuvector/templates/guppy-nvsecurityrule.yaml @@ -0,0 +1,129 @@ +{{- if .Values.policies.include }} +apiVersion: neuvector.com/v1 +kind: NvSecurityRule +metadata: + name: nv.guppy-deployment.{{ .Release.Namespace }} +spec: + dlp: + settings: [] + status: true + egress: + - action: allow + applications: + - DNS + name: nv.kube-dns.kube-system-egress-15 + ports: any + priority: 0 + selector: + comment: "" + criteria: + - key: service + op: = + value: kube-dns.kube-system + - key: domain + op: = + value: kube-system + name: nv.kube-dns.kube-system + original_name: "" + file: [] + ingress: + - action: allow + applications: + - HTTP + name: nv.guppy-deployment.{{ .Release.Namespace }}-ingress-42 + ports: any + priority: 0 + selector: + comment: "" + name: Workload:ingress + original_name: "" + - action: allow + applications: + - any + name: nv.guppy-deployment.{{ .Release.Namespace }}-ingress-43 + ports: tcp/8000 + priority: 0 + selector: + comment: "" + name: Workload:ingress + original_name: "" + - action: allow + applications: + - SSL + name: nv.guppy-deployment.{{ .Release.Namespace }}-ingress-44 + ports: any + priority: 0 + selector: + comment: "" + criteria: [] + name: external + original_name: "" + - action: allow + applications: + - HTTP + name: nv.guppy-deployment.{{ .Release.Namespace }}-ingress-45 + ports: any + priority: 0 + selector: + comment: "" + criteria: + - key: service + op: = + value: revproxy-deployment.{{ .Release.Namespace }} + - key: domain + op: = + value: {{ .Release.Namespace }} + name: nv.revproxy-deployment.{{ .Release.Namespace }} + original_name: "" + process: + - action: allow + allow_update: false + name: bash + path: /usr/bin/bash + - action: allow + allow_update: false + name: cat + path: /usr/bin/cat + - action: allow + allow_update: false + name: dash + path: /usr/bin/dash + - action: allow + allow_update: false + name: ls + path: /usr/bin/ls + - action: allow + allow_update: false + name: node + path: /usr/bin/node + - action: allow + allow_update: false + name: pause + path: /pause + - action: allow + allow_update: false + name: runc + path: /usr/bin/runc + - action: allow + allow_update: false + name: sh + path: /usr/bin/dash + process_profile: + baseline: zero-drift + target: + policymode: {{ .Values.policies.policyMode }} + selector: + comment: "" + criteria: + - key: service + op: = + value: guppy-deployment.{{ .Release.Namespace }} + - key: domain + op: = + value: {{ .Release.Namespace }} + name: nv.guppy-deployment.{{ .Release.Namespace }} + original_name: "" + waf: + settings: [] + status: true +{{- end }} \ No newline at end of file diff --git a/helm/neuvector/templates/hatchery-nvsecurityrule.yaml b/helm/neuvector/templates/hatchery-nvsecurityrule.yaml new file mode 100644 index 00000000..cf46a487 --- /dev/null +++ b/helm/neuvector/templates/hatchery-nvsecurityrule.yaml @@ -0,0 +1,140 @@ +{{- if .Values.policies.include }} +apiVersion: neuvector.com/v1 +kind: NvSecurityRule +metadata: + name: nv.hatchery-deployment.{{ .Release.Namespace }} +spec: + dlp: + settings: [] + status: true + egress: + - action: allow + applications: + - DNS + name: nv.kube-dns.kube-system-egress-16 + ports: any + priority: 0 + selector: + comment: "" + criteria: + - key: service + op: = + value: kube-dns.kube-system + - key: domain + op: = + value: kube-system + name: nv.kube-dns.kube-system + original_name: "" + - action: allow + applications: + - SSL + name: nv.{{ .Values.ingress.controller }}.{{ .Values.ingress.namespace }}-egress-17 + ports: any + priority: 0 + selector: + comment: "" + criteria: + - key: service + op: = + value: {{ .Values.ingress.controller }}.{{ .Values.ingress.namespace }} + - key: domain + op: = + value: {{ .Values.ingress.class }} + name: nv.{{ .Values.ingress.controller }}.{{ .Values.ingress.namespace }} + original_name: "" + - action: allow + applications: + - SSL + name: external-egress-18 + ports: any + priority: 0 + selector: + comment: "" + criteria: [] + name: external + original_name: "" + - action: allow + applications: + - SSL + name: nv.revproxy-deployment.{{ .Release.Namespace }}-egress-19 + ports: any + priority: 0 + selector: + comment: "" + criteria: + - key: service + op: = + value: revproxy-deployment.{{ .Release.Namespace }} + - key: domain + op: = + value: {{ .Release.Namespace }} + name: nv.revproxy-deployment.{{ .Release.Namespace }} + original_name: "" + file: [] + ingress: + - action: allow + applications: + - HTTP + name: nv.hatchery-deployment.{{ .Release.Namespace }}-ingress-46 + ports: any + priority: 0 + selector: + comment: "" + name: Workload:ingress + original_name: "" + - action: allow + applications: + - SSL + name: nv.hatchery-deployment.{{ .Release.Namespace }}-ingress-47 + ports: any + priority: 0 + selector: + comment: "" + criteria: [] + name: external + original_name: "" + - action: allow + applications: + - HTTP + name: nv.hatchery-deployment.{{ .Release.Namespace }}-ingress-48 + ports: any + priority: 0 + selector: + comment: "" + criteria: + - key: service + op: = + value: revproxy-deployment.{{ .Release.Namespace }} + - key: domain + op: = + value: {{ .Release.Namespace }} + name: nv.revproxy-deployment.{{ .Release.Namespace }} + original_name: "" + process: + - action: allow + allow_update: false + name: hatchery + path: /hatchery + - action: allow + allow_update: false + name: pause + path: /pause + process_profile: + baseline: zero-drift + target: + policymode: {{ .Values.policies.policyMode }} + selector: + comment: "" + criteria: + - key: service + op: = + value: hatchery-deployment.{{ .Release.Namespace }} + - key: domain + op: = + value: {{ .Release.Namespace }} + name: nv.hatchery-deployment.{{ .Release.Namespace }} + original_name: "" + waf: + settings: [] + status: true +{{- end }} \ No newline at end of file diff --git a/helm/neuvector/templates/indexd-nvsecurityrule.yaml b/helm/neuvector/templates/indexd-nvsecurityrule.yaml new file mode 100644 index 00000000..db1e1000 --- /dev/null +++ b/helm/neuvector/templates/indexd-nvsecurityrule.yaml @@ -0,0 +1,152 @@ +{{- if .Values.policies.include }} +apiVersion: neuvector.com/v1 +kind: NvSecurityRule +metadata: + name: nv.indexd-deployment.{{ .Release.Namespace }} +spec: + dlp: + settings: [] + status: true + egress: + - action: allow + applications: + - DNS + name: nv.kube-dns.kube-system-egress-20 + ports: any + priority: 0 + selector: + comment: "" + criteria: + - key: service + op: = + value: kube-dns.kube-system + - key: domain + op: = + value: kube-system + name: nv.kube-dns.kube-system + original_name: "" + file: [] + ingress: + - action: allow + applications: + - HTTP + name: nv.indexd-deployment.{{ .Release.Namespace }}-ingress-49 + ports: any + priority: 0 + selector: + comment: "" + name: Workload:ingress + original_name: "" + - action: allow + applications: + - SSL + name: nv.indexd-deployment.{{ .Release.Namespace }}-ingress-50 + ports: any + priority: 0 + selector: + comment: "" + criteria: [] + name: external + original_name: "" + - action: allow + applications: + - HTTP + name: nv.indexd-deployment.{{ .Release.Namespace }}-ingress-51 + ports: any + priority: 0 + selector: + comment: "" + criteria: + - key: service + op: = + value: revproxy-deployment.{{ .Release.Namespace }} + - key: domain + op: = + value: {{ .Release.Namespace }} + name: nv.revproxy-deployment.{{ .Release.Namespace }} + original_name: "" + - action: allow + applications: + - HTTP + name: nv.indexd-deployment.{{ .Release.Namespace }}-ingress-52 + ports: any + priority: 0 + selector: + comment: "" + criteria: + - key: service + op: = + value: sheepdog-deployment.{{ .Release.Namespace }} + - key: domain + op: = + value: {{ .Release.Namespace }} + name: nv.sheepdog-deployment.{{ .Release.Namespace }} + original_name: "" + process: + - action: allow + allow_update: false + name: bash + path: /bin/bash + - action: allow + allow_update: false + name: chmod + path: /bin/chmod + - action: allow + allow_update: false + name: chown + path: /bin/chown + - action: allow + allow_update: false + name: dockerrun.sh + path: /bin/dash + - action: allow + allow_update: false + name: mkdir + path: /bin/mkdir + - action: allow + allow_update: false + name: mv + path: /bin/mv + - action: allow + allow_update: false + name: nginx + path: /usr/sbin/nginx + - action: allow + allow_update: false + name: pause + path: /pause + - action: allow + allow_update: false + name: rm + path: /bin/rm + - action: allow + allow_update: false + name: run-parts + path: /bin/run-parts + - action: allow + allow_update: false + name: sh + path: /bin/dash + - action: allow + allow_update: false + name: uwsgi + path: /usr/local/bin/uwsgi + process_profile: + baseline: zero-drift + target: + policymode: {{ .Values.policies.policyMode }} + selector: + comment: "" + criteria: + - key: service + op: = + value: indexd-deployment.{{ .Release.Namespace }} + - key: domain + op: = + value: {{ .Release.Namespace }} + name: nv.indexd-deployment.{{ .Release.Namespace }} + original_name: "" + waf: + settings: [] + status: true +{{- end }} \ No newline at end of file diff --git a/helm/neuvector/templates/ingress-nvclustersecurityrule.yaml b/helm/neuvector/templates/ingress-nvclustersecurityrule.yaml new file mode 100644 index 00000000..febb5ef0 --- /dev/null +++ b/helm/neuvector/templates/ingress-nvclustersecurityrule.yaml @@ -0,0 +1,130 @@ +{{- if .Values.policies.include }} +apiVersion: neuvector.com/v1 +kind: NvClusterSecurityRule +metadata: + name: {{ .Release.Namespace }} + namespace: "" +spec: + dlp: + settings: [] + status: true + egress: [] + file: [] + ingress: + - action: allow + applications: + - any + name: {{ .Release.Namespace }}-ingress-0 + ports: tcp/8089 + priority: 0 + selector: + comment: "" + criteria: + - key: service + op: = + value: {{ .Values.ingress.controller }}.{{ .Values.ingress.namespace }} + - key: domain + op: = + value: {{ .Values.ingress.class }} + name: nv.{{ .Values.ingress.controller }}.{{ .Values.ingress.namespace }} + original_name: "" + - action: allow + applications: + - any + name: {{ .Release.Namespace }}-ingress-1 + ports: tcp/8089 + priority: 0 + selector: + comment: "" + criteria: + - key: service + op: = + value: {{ .Values.ingress.controller }}.{{ .Values.ingress.namespace }} + - key: domain + op: = + value: {{ .Values.ingress.class }} + name: nv.{{ .Values.ingress.controller }}.{{ .Values.ingress.namespace }} + original_name: "" + - action: allow + applications: + - any + name: {{ .Release.Namespace }}-ingress-2 + ports: tcp/8089 + priority: 0 + selector: + comment: "" + criteria: + - key: service + op: = + value: {{ .Values.ingress.controller }}.{{ .Values.ingress.namespace }} + - key: domain + op: = + value: {{ .Values.ingress.class }} + name: nv.{{ .Values.ingress.controller }}.{{ .Values.ingress.namespace }} + original_name: "" + - action: allow + applications: + - any + name: {{ .Release.Namespace }}-ingress-3 + ports: tcp/8089 + priority: 0 + selector: + comment: "" + criteria: + - key: service + op: = + value: {{ .Values.ingress.controller }}.{{ .Values.ingress.namespace }} + - key: domain + op: = + value: {{ .Values.ingress.class }} + name: nv.{{ .Values.ingress.controller }}.{{ .Values.ingress.namespace }} + original_name: "" + - action: allow + applications: + - any + name: {{ .Release.Namespace }}-ingress-4 + ports: tcp/8089 + priority: 0 + selector: + comment: "" + criteria: + - key: service + op: = + value: {{ .Values.ingress.controller }}.{{ .Values.ingress.namespace }} + - key: domain + op: = + value: {{ .Values.ingress.class }} + name: nv.{{ .Values.ingress.controller }}.{{ .Values.ingress.namespace }} + original_name: "" + - action: deny + applications: + - any + name: {{ .Release.Namespace }}-ingress-5 + ports: any + priority: 0 + selector: + comment: "" + criteria: + - key: service + op: = + value: {{ .Values.ingress.controller }}.{{ .Values.ingress.namespace }} + - key: domain + op: = + value: {{ .Values.ingress.class }} + name: nv.{{ .Values.ingress.controller }}.{{ .Values.ingress.namespace }} + original_name: "" + process: [] + target: + policymode: N/A + selector: + comment: gen3 development group + criteria: + - key: namespace + op: = + value: {{ .Release.Namespace }} + name: {{ .Release.Namespace }} + original_name: "" + waf: + settings: [] + status: true +{{- end }} \ No newline at end of file diff --git a/helm/neuvector/templates/manifestservice-nvsecurityrule.yaml b/helm/neuvector/templates/manifestservice-nvsecurityrule.yaml new file mode 100644 index 00000000..1efd07f5 --- /dev/null +++ b/helm/neuvector/templates/manifestservice-nvsecurityrule.yaml @@ -0,0 +1,166 @@ +{{- if .Values.policies.include }} +apiVersion: neuvector.com/v1 +kind: NvSecurityRule +metadata: + name: nv.manifestservice-deployment.{{ .Release.Namespace }} +spec: + dlp: + settings: [] + status: true + egress: + - action: allow + applications: + - DNS + name: nv.kube-dns.kube-system-egress-21 + ports: any + priority: 0 + selector: + comment: "" + criteria: + - key: service + op: = + value: kube-dns.kube-system + - key: domain + op: = + value: kube-system + name: nv.kube-dns.kube-system + original_name: "" + file: [] + ingress: + - action: allow + applications: + - HTTP + name: nv.manifestservice-deployment.{{ .Release.Namespace }}-ingress-53 + ports: any + priority: 0 + selector: + comment: "" + name: Workload:ingress + original_name: "" + - action: allow + applications: + - any + name: nv.manifestservice-deployment.{{ .Release.Namespace }}-ingress-54 + ports: tcp/80 + priority: 0 + selector: + comment: "" + name: Workload:ingress + original_name: "" + - action: allow + applications: + - HTTP + name: nv.manifestservice-deployment.{{ .Release.Namespace }}-ingress-55 + ports: any + priority: 0 + selector: + comment: "" + criteria: + - key: service + op: = + value: revproxy-deployment.{{ .Release.Namespace }} + - key: domain + op: = + value: {{ .Release.Namespace }} + name: nv.revproxy-deployment.{{ .Release.Namespace }} + original_name: "" + process: + - action: allow + allow_update: false + name: basename + path: /usr/bin/basename + - action: allow + allow_update: false + name: cat + path: /bin/cat + - action: allow + allow_update: false + name: chmod + path: /bin/chmod + - action: allow + allow_update: false + name: dockerrun.sh + path: /bin/dash + - action: allow + allow_update: false + name: find + path: /usr/bin/find + - action: allow + allow_update: false + name: grep + path: /bin/grep + - action: allow + allow_update: false + name: ldconfig + path: /sbin/ldconfig + - action: allow + allow_update: false + name: mkdir + path: /bin/mkdir + - action: allow + allow_update: false + name: mktemp + path: /bin/mktemp + - action: allow + allow_update: false + name: mv + path: /bin/mv + - action: allow + allow_update: false + name: nginx + path: /usr/sbin/nginx + - action: allow + allow_update: false + name: pause + path: /pause + - action: allow + allow_update: false + name: readlink + path: /bin/readlink + - action: allow + allow_update: false + name: rm + path: /bin/rm + - action: allow + allow_update: false + name: run-parts + path: /bin/run-parts + - action: allow + allow_update: false + name: sed + path: /bin/sed + - action: allow + allow_update: false + name: sh + path: /bin/dash + - action: allow + allow_update: false + name: sort + path: /usr/bin/sort + - action: allow + allow_update: false + name: uwsgi + path: /usr/local/bin/uwsgi + - action: allow + allow_update: false + name: wc + path: /usr/bin/wc + process_profile: + baseline: zero-drift + target: + policymode: {{ .Values.policies.policyMode }} + selector: + comment: "" + criteria: + - key: service + op: = + value: manifestservice-deployment.{{ .Release.Namespace }} + - key: domain + op: = + value: {{ .Release.Namespace }} + name: nv.manifestservice-deployment.{{ .Release.Namespace }} + original_name: "" + waf: + settings: [] + status: true +{{- end }} \ No newline at end of file diff --git a/helm/neuvector/templates/metadata-nvsecurityrule.yaml b/helm/neuvector/templates/metadata-nvsecurityrule.yaml new file mode 100644 index 00000000..3d85201c --- /dev/null +++ b/helm/neuvector/templates/metadata-nvsecurityrule.yaml @@ -0,0 +1,87 @@ +{{- if .Values.policies.include }} +apiVersion: neuvector.com/v1 +kind: NvSecurityRule +metadata: + name: nv.metadata-deployment.{{ .Release.Namespace }} +spec: + dlp: + settings: [] + status: true + egress: + - action: allow + applications: + - DNS + name: nv.kube-dns.kube-system-egress-22 + ports: any + priority: 0 + selector: + comment: "" + criteria: + - key: service + op: = + value: kube-dns.kube-system + - key: domain + op: = + value: kube-system + name: nv.kube-dns.kube-system + original_name: "" + file: [] + ingress: + - action: allow + applications: + - HTTP + name: nv.metadata-deployment.{{ .Release.Namespace }}-ingress-56 + ports: any + priority: 0 + selector: + comment: "" + name: Workload:ingress + original_name: "" + process: + - action: allow + allow_update: false + name: alembic + path: /usr/local/bin/python3.9 + - action: allow + allow_update: false + name: grep + path: /bin/grep + - action: allow + allow_update: false + name: gunicorn + path: /usr/local/bin/python3.9 + - action: allow + allow_update: false + name: pause + path: /pause + - action: allow + allow_update: false + name: runc + path: /usr/bin/runc + - action: allow + allow_update: false + name: sed + path: /bin/sed + - action: allow + allow_update: false + name: sh + path: /bin/dash + process_profile: + baseline: zero-drift + target: + policymode: {{ .Values.policies.policyMode }} + selector: + comment: "" + criteria: + - key: service + op: = + value: metadata-deployment.{{ .Release.Namespace }} + - key: domain + op: = + value: {{ .Release.Namespace }} + name: nv.metadata-deployment.{{ .Release.Namespace }} + original_name: "" + waf: + settings: [] + status: true +{{- end }} \ No newline at end of file diff --git a/helm/neuvector/templates/peregrine-nvsecurityrule.yaml b/helm/neuvector/templates/peregrine-nvsecurityrule.yaml new file mode 100644 index 00000000..f9df4477 --- /dev/null +++ b/helm/neuvector/templates/peregrine-nvsecurityrule.yaml @@ -0,0 +1,258 @@ +{{- if .Values.policies.include }} +apiVersion: neuvector.com/v1 +kind: NvSecurityRule +metadata: + name: nv.peregrine-deployment.{{ .Release.Namespace }} +spec: + dlp: + settings: [] + status: true + egress: + - action: allow + applications: + - DNS + name: nv.kube-dns.kube-system-egress-23 + ports: any + priority: 0 + selector: + comment: "" + criteria: + - key: service + op: = + value: kube-dns.kube-system + - key: domain + op: = + value: kube-system + name: nv.kube-dns.kube-system + original_name: "" + - action: allow + applications: + - SSL + name: nv.revproxy-deployment.{{ .Release.Namespace }}-egress-24 + ports: any + priority: 0 + selector: + comment: "" + criteria: + - key: service + op: = + value: revproxy-deployment.{{ .Release.Namespace }} + - key: domain + op: = + value: {{ .Release.Namespace }} + name: nv.revproxy-deployment.{{ .Release.Namespace }} + original_name: "" + - action: allow + applications: + - HTTP + - SSL + name: external-egress-25 + ports: any + priority: 0 + selector: + comment: "" + criteria: [] + name: external + original_name: "" + - action: allow + applications: + - HTTP + - SSL + name: nv.{{ .Values.ingress.controller }}.{{ .Values.ingress.namespace }}-egress-26 + ports: any + priority: 0 + selector: + comment: "" + criteria: + - key: service + op: = + value: {{ .Values.ingress.controller }}.{{ .Values.ingress.namespace }} + - key: domain + op: = + value: {{ .Values.ingress.class }} + name: nv.{{ .Values.ingress.controller }}.{{ .Values.ingress.namespace }} + original_name: "" + file: [] + ingress: + - action: allow + applications: + - HTTP + name: nv.peregrine-deployment.{{ .Release.Namespace }}-ingress-57 + ports: any + priority: 0 + selector: + comment: "" + name: Workload:ingress + original_name: "" + - action: allow + applications: + - HTTP + name: nv.peregrine-deployment.{{ .Release.Namespace }}-ingress-58 + ports: any + priority: 0 + selector: + comment: "" + criteria: + - key: service + op: = + value: pidgin-deployment.{{ .Release.Namespace }} + - key: domain + op: = + value: {{ .Release.Namespace }} + name: nv.pidgin-deployment.{{ .Release.Namespace }} + original_name: "" + - action: allow + applications: + - SSL + name: nv.peregrine-deployment.{{ .Release.Namespace }}-ingress-59 + ports: any + priority: 0 + selector: + comment: "" + criteria: [] + name: external + original_name: "" + - action: allow + applications: + - HTTP + name: nv.peregrine-deployment.{{ .Release.Namespace }}-ingress-60 + ports: any + priority: 0 + selector: + comment: "" + criteria: + - key: service + op: = + value: revproxy-deployment.{{ .Release.Namespace }} + - key: domain + op: = + value: {{ .Release.Namespace }} + name: nv.revproxy-deployment.{{ .Release.Namespace }} + original_name: "" + - action: allow + applications: + - any + name: nv.peregrine-deployment.{{ .Release.Namespace }}-ingress-61 + ports: tcp/80 + priority: 0 + selector: + comment: "" + name: Workload:ingress + original_name: "" + - action: allow + applications: + - HTTP + name: nv.peregrine-deployment.{{ .Release.Namespace }}-ingress-62 + ports: any + priority: 0 + selector: + comment: "" + criteria: + - key: service + op: = + value: portal-deployment.{{ .Release.Namespace }} + - key: domain + op: = + value: {{ .Release.Namespace }} + name: nv.portal-deployment.{{ .Release.Namespace }} + original_name: "" + process: + - action: allow + allow_update: false + name: basename + path: /usr/bin/basename + - action: allow + allow_update: false + name: cat + path: /bin/cat + - action: allow + allow_update: false + name: chmod + path: /bin/chmod + - action: allow + allow_update: false + name: dash + path: /bin/dash + - action: allow + allow_update: false + name: dockerrun.sh + path: /bin/dash + - action: allow + allow_update: false + name: find + path: /usr/bin/find + - action: allow + allow_update: false + name: grep + path: /bin/grep + - action: allow + allow_update: false + name: mkdir + path: /bin/mkdir + - action: allow + allow_update: false + name: mktemp + path: /bin/mktemp + - action: allow + allow_update: false + name: mv + path: /bin/mv + - action: allow + allow_update: false + name: nginx + path: /usr/sbin/nginx + - action: allow + allow_update: false + name: pause + path: /pause + - action: allow + allow_update: false + name: readlink + path: /bin/readlink + - action: allow + allow_update: false + name: rm + path: /bin/rm + - action: allow + allow_update: false + name: run-parts + path: /bin/run-parts + - action: allow + allow_update: false + name: sed + path: /bin/sed + - action: allow + allow_update: false + name: sh + path: /bin/dash + - action: allow + allow_update: false + name: sort + path: /usr/bin/sort + - action: allow + allow_update: false + name: uwsgi + path: /usr/local/bin/uwsgi + - action: allow + allow_update: false + name: wc + path: /usr/bin/wc + process_profile: + baseline: zero-drift + target: + policymode: {{ .Values.policies.policyMode }} + selector: + comment: "" + criteria: + - key: service + op: = + value: peregrine-deployment.{{ .Release.Namespace }} + - key: domain + op: = + value: {{ .Release.Namespace }} + name: nv.peregrine-deployment.{{ .Release.Namespace }} + original_name: "" + waf: + settings: [] + status: true +{{- end }} \ No newline at end of file diff --git a/helm/neuvector/templates/pidgin-nvsecurityrule.yaml b/helm/neuvector/templates/pidgin-nvsecurityrule.yaml new file mode 100644 index 00000000..8f68b21a --- /dev/null +++ b/helm/neuvector/templates/pidgin-nvsecurityrule.yaml @@ -0,0 +1,135 @@ +{{- if .Values.policies.include }} +apiVersion: neuvector.com/v1 +kind: NvSecurityRule +metadata: + name: nv.pidgin-deployment.{{ .Release.Namespace }} +spec: + dlp: + settings: [] + status: true + egress: + - action: allow + applications: + - DNS + name: nv.kube-dns.kube-system-egress-27 + ports: any + priority: 0 + selector: + comment: "" + criteria: + - key: service + op: = + value: kube-dns.kube-system + - key: domain + op: = + value: kube-system + name: nv.kube-dns.kube-system + original_name: "" + file: [] + ingress: + - action: allow + applications: + - HTTP + name: nv.pidgin-deployment.{{ .Release.Namespace }}-ingress-63 + ports: any + priority: 0 + selector: + comment: "" + name: Workload:ingress + original_name: "" + process: + - action: allow + allow_update: false + name: basename + path: /usr/bin/basename + - action: allow + allow_update: false + name: chmod + path: /bin/chmod + - action: allow + allow_update: false + name: dash + path: /bin/dash + - action: allow + allow_update: false + name: dockerrun.sh + path: /bin/dash + - action: allow + allow_update: false + name: find + path: /usr/bin/find + - action: allow + allow_update: false + name: grep + path: /bin/grep + - action: allow + allow_update: false + name: mkdir + path: /bin/mkdir + - action: allow + allow_update: false + name: mktemp + path: /bin/mktemp + - action: allow + allow_update: false + name: mv + path: /bin/mv + - action: allow + allow_update: false + name: nginx + path: /usr/sbin/nginx + - action: allow + allow_update: false + name: pause + path: /pause + - action: allow + allow_update: false + name: readlink + path: /bin/readlink + - action: allow + allow_update: false + name: rm + path: /bin/rm + - action: allow + allow_update: false + name: run-parts + path: /bin/run-parts + - action: allow + allow_update: false + name: sed + path: /bin/sed + - action: allow + allow_update: false + name: sh + path: /bin/dash + - action: allow + allow_update: false + name: sort + path: /usr/bin/sort + - action: allow + allow_update: false + name: uwsgi + path: /usr/local/bin/uwsgi + - action: allow + allow_update: false + name: wc + path: /usr/bin/wc + process_profile: + baseline: zero-drift + target: + policymode: {{ .Values.policies.policyMode }} + selector: + comment: "" + criteria: + - key: service + op: = + value: pidgin-deployment.{{ .Release.Namespace }} + - key: domain + op: = + value: {{ .Release.Namespace }} + name: nv.pidgin-deployment.{{ .Release.Namespace }} + original_name: "" + waf: + settings: [] + status: true +{{- end }} \ No newline at end of file diff --git a/helm/neuvector/templates/portal-nvsecurityrule.yaml b/helm/neuvector/templates/portal-nvsecurityrule.yaml new file mode 100644 index 00000000..0bbb87f3 --- /dev/null +++ b/helm/neuvector/templates/portal-nvsecurityrule.yaml @@ -0,0 +1,182 @@ +{{- if .Values.policies.include }} +apiVersion: neuvector.com/v1 +kind: NvSecurityRule +metadata: + name: nv.portal-deployment.{{ .Release.Namespace }} +spec: + dlp: + settings: [] + status: true + egress: + - action: allow + applications: + - any + name: nv.revproxy-deployment.{{ .Release.Namespace }}-egress-28 + ports: tcp/80 + priority: 0 + selector: + comment: "" + criteria: + - key: service + op: = + value: revproxy-deployment.{{ .Release.Namespace }} + - key: domain + op: = + value: {{ .Release.Namespace }} + name: nv.revproxy-deployment.{{ .Release.Namespace }} + original_name: "" + - action: allow + applications: + - any + name: nv.revproxy-deployment.{{ .Release.Namespace }}-egress-29 + ports: tcp/80 + priority: 0 + selector: + comment: "" + criteria: + - key: service + op: = + value: revproxy-deployment.{{ .Release.Namespace }} + - key: domain + op: = + value: {{ .Release.Namespace }} + name: nv.revproxy-deployment.{{ .Release.Namespace }} + original_name: "" + - action: allow + applications: + - any + name: nv.revproxy-deployment.{{ .Release.Namespace }}-egress-30 + ports: tcp/80 + priority: 0 + selector: + comment: "" + criteria: + - key: service + op: = + value: revproxy-deployment.{{ .Release.Namespace }} + - key: domain + op: = + value: {{ .Release.Namespace }} + name: nv.revproxy-deployment.{{ .Release.Namespace }} + original_name: "" + - action: allow + applications: + - HTTP + name: nv.sheepdog-deployment.{{ .Release.Namespace }}-egress-31 + ports: any + priority: 0 + selector: + comment: "" + criteria: + - key: service + op: = + value: sheepdog-deployment.{{ .Release.Namespace }} + - key: domain + op: = + value: {{ .Release.Namespace }} + name: nv.sheepdog-deployment.{{ .Release.Namespace }} + original_name: "" + file: [] + ingress: + - action: allow + applications: + - HTTP + name: nv.portal-deployment.{{ .Release.Namespace }}-ingress-64 + ports: any + priority: 0 + selector: + comment: "" + name: Workload:ingress + original_name: "" + - action: allow + applications: + - HTTP + name: nv.portal-deployment.{{ .Release.Namespace }}-ingress-65 + ports: any + priority: 0 + selector: + comment: "" + criteria: + - key: service + op: = + value: revproxy-deployment.{{ .Release.Namespace }} + - key: domain + op: = + value: {{ .Release.Namespace }} + name: nv.revproxy-deployment.{{ .Release.Namespace }} + original_name: "" + - action: allow + applications: + - SSL + name: nv.portal-deployment.{{ .Release.Namespace }}-ingress-66 + ports: any + priority: 0 + selector: + comment: "" + criteria: [] + name: external + original_name: "" + process: + - action: allow + allow_update: false + name: bash + path: /usr/bin/bash + - action: allow + allow_update: false + name: nginx + path: /usr/sbin/nginx + - action: allow + allow_update: false + name: node + path: /usr/bin/node + - action: allow + allow_update: false + name: npm + path: /usr/bin/env + - action: allow + allow_update: false + name: npm + path: /usr/bin/node + - action: allow + allow_update: false + name: npx + path: /usr/bin/env + - action: allow + allow_update: false + name: pause + path: /pause + - action: allow + allow_update: false + name: relay-compiler + path: /usr/bin/env + - action: allow + allow_update: false + name: sh + path: /usr/bin/dash + - action: allow + allow_update: false + name: webpack + path: /usr/bin/env + - action: allow + allow_update: false + name: webpack + path: /usr/bin/node + process_profile: + baseline: zero-drift + target: + policymode: {{ .Values.policies.policyMode }} + selector: + comment: "" + criteria: + - key: service + op: = + value: portal-deployment.{{ .Release.Namespace }} + - key: domain + op: = + value: {{ .Release.Namespace }} + name: nv.portal-deployment.{{ .Release.Namespace }} + original_name: "" + waf: + settings: [] + status: true +{{- end }} \ No newline at end of file diff --git a/helm/neuvector/templates/postgresql-nvsecurityrule.yaml b/helm/neuvector/templates/postgresql-nvsecurityrule.yaml new file mode 100644 index 00000000..d1d1f076 --- /dev/null +++ b/helm/neuvector/templates/postgresql-nvsecurityrule.yaml @@ -0,0 +1,138 @@ +{{- if .Values.policies.include }} +apiVersion: neuvector.com/v1 +kind: NvSecurityRule +metadata: + name: nv.{{ .Values.DB_HOST }}.{{ .Release.Namespace }} +spec: + dlp: + settings: [] + status: true + egress: [] + file: [] + ingress: + - action: allow + applications: + - PostgreSQL + name: nv.{{ .Values.DB_HOST }}.{{ .Release.Namespace }}-ingress-25 + ports: any + priority: 0 + selector: + comment: "" + criteria: + - key: service + op: = + value: peregrine-deployment.{{ .Release.Namespace }} + - key: domain + op: = + value: {{ .Release.Namespace }} + name: nv.peregrine-deployment.{{ .Release.Namespace }} + original_name: "" + - action: allow + applications: + - PostgreSQL + name: nv.{{ .Values.DB_HOST }}.{{ .Release.Namespace }}-ingress-26 + ports: any + priority: 0 + selector: + comment: "" + criteria: + - key: service + op: = + value: sheepdog-deployment.{{ .Release.Namespace }} + - key: domain + op: = + value: {{ .Release.Namespace }} + name: nv.sheepdog-deployment.{{ .Release.Namespace }} + original_name: "" + - action: allow + applications: + - PostgreSQL + name: nv.{{ .Values.DB_HOST }}.{{ .Release.Namespace }}-ingress-27 + ports: any + priority: 0 + selector: + comment: "" + criteria: + - key: service + op: = + value: indexd-deployment.{{ .Release.Namespace }} + - key: domain + op: = + value: {{ .Release.Namespace }} + name: nv.indexd-deployment.{{ .Release.Namespace }} + original_name: "" + - action: allow + applications: + - PostgreSQL + name: nv.{{ .Values.DB_HOST }}.{{ .Release.Namespace }}-ingress-28 + ports: any + priority: 0 + selector: + comment: "" + criteria: + - key: service + op: = + value: metadata-deployment.{{ .Release.Namespace }} + - key: domain + op: = + value: {{ .Release.Namespace }} + name: nv.metadata-deployment.{{ .Release.Namespace }} + original_name: "" + - action: allow + applications: + - PostgreSQL + name: nv.{{ .Values.DB_HOST }}.{{ .Release.Namespace }}-ingress-29 + ports: any + priority: 0 + selector: + comment: "" + criteria: + - key: service + op: = + value: presigned-url-fence-deployment.{{ .Release.Namespace }} + - key: domain + op: = + value: {{ .Release.Namespace }} + name: nv.presigned-url-fence-deployment.{{ .Release.Namespace }} + original_name: "" + - action: allow + applications: + - PostgreSQL + name: nv.{{ .Values.DB_HOST }}.{{ .Release.Namespace }}-ingress-30 + ports: any + priority: 0 + selector: + comment: "" + criteria: + - key: service + op: = + value: fence-deployment.{{ .Release.Namespace }} + - key: domain + op: = + value: {{ .Release.Namespace }} + name: nv.fence-deployment.{{ .Release.Namespace }} + original_name: "" + process: + - action: allow + allow_update: false + name: sh + path: '*' + process_profile: + baseline: zero-drift + target: + policymode: {{ .Values.policies.policyMode }} + selector: + comment: "" + criteria: + - key: service + op: = + value: {{ .Values.DB_HOST }}.{{ .Release.Namespace }} + - key: domain + op: = + value: {{ .Release.Namespace }} + name: nv.{{ .Values.DB_HOST }}.{{ .Release.Namespace }} + original_name: "" + waf: + settings: [] + status: true +{{- end }} \ No newline at end of file diff --git a/helm/neuvector/templates/presigned-url-fence-nvsecurityrule.yaml b/helm/neuvector/templates/presigned-url-fence-nvsecurityrule.yaml new file mode 100644 index 00000000..5677d408 --- /dev/null +++ b/helm/neuvector/templates/presigned-url-fence-nvsecurityrule.yaml @@ -0,0 +1,173 @@ +{{- if .Values.policies.include }} +apiVersion: neuvector.com/v1 +kind: NvSecurityRule +metadata: + name: nv.presigned-url-fence-deployment.{{ .Release.Namespace }} +spec: + dlp: + settings: [] + status: true + egress: + - action: allow + applications: + - any + name: nodes-egress-32 + ports: tcp/8126 + priority: 0 + selector: + comment: "" + criteria: [] + name: nodes + original_name: "" + - action: allow + applications: + - SSL + name: external-egress-33 + ports: any + priority: 0 + selector: + comment: "" + criteria: [] + name: external + original_name: "" + - action: allow + applications: + - DNS + name: nv.kube-dns.kube-system-egress-34 + ports: any + priority: 0 + selector: + comment: "" + criteria: + - key: service + op: = + value: kube-dns.kube-system + - key: domain + op: = + value: kube-system + name: nv.kube-dns.kube-system + original_name: "" + file: [] + ingress: + - action: allow + applications: + - HTTP + name: nv.presigned-url-fence-deployment.{{ .Release.Namespace }}-ingress-67 + ports: any + priority: 0 + selector: + comment: "" + name: Workload:ingress + original_name: "" + process: + - action: allow + allow_update: false + name: basename + path: /usr/bin/basename + - action: allow + allow_update: false + name: bash + path: /bin/bash + - action: allow + allow_update: false + name: cat + path: /bin/cat + - action: allow + allow_update: false + name: chmod + path: /bin/chmod + - action: allow + allow_update: false + name: chown + path: /bin/chown + - action: allow + allow_update: false + name: ddtrace-run + path: /usr/local/bin/python3.9 + - action: allow + allow_update: false + name: find + path: /usr/bin/find + - action: allow + allow_update: false + name: ldconfig + path: /sbin/ldconfig + - action: allow + allow_update: false + name: mkdir + path: /bin/mkdir + - action: allow + allow_update: false + name: mktemp + path: /bin/mktemp + - action: allow + allow_update: false + name: mv + path: /bin/mv + - action: allow + allow_update: false + name: nginx + path: /usr/sbin/nginx + - action: allow + allow_update: false + name: pause + path: /pause + - action: allow + allow_update: false + name: pip + path: /usr/local/bin/python3.9 + - action: allow + allow_update: false + name: readlink + path: /bin/readlink + - action: allow + allow_update: false + name: rm + path: /bin/rm + - action: allow + allow_update: false + name: run-parts + path: /bin/run-parts + - action: allow + allow_update: false + name: sed + path: /bin/sed + - action: allow + allow_update: false + name: sh + path: /bin/dash + - action: allow + allow_update: false + name: sort + path: /usr/bin/sort + - action: allow + allow_update: false + name: uname + path: /bin/uname + - action: allow + allow_update: false + name: uwsgi + path: /usr/local/bin/uwsgi + - action: allow + allow_update: false + name: wc + path: /usr/bin/wc + process_profile: + baseline: zero-drift + target: + policymode: {{ .Values.policies.policyMode }} + selector: + comment: "" + criteria: + - key: service + op: = + value: presigned-url-fence-deployment.{{ .Release.Namespace }} + - key: domain + op: = + value: {{ .Release.Namespace }} + name: nv.presigned-url-fence-deployment.{{ .Release.Namespace }} + original_name: "" + waf: + settings: [] + status: true +{{- end }} \ No newline at end of file diff --git a/helm/neuvector/templates/revproxy-nvsecurityrule.yaml b/helm/neuvector/templates/revproxy-nvsecurityrule.yaml new file mode 100644 index 00000000..3661369b --- /dev/null +++ b/helm/neuvector/templates/revproxy-nvsecurityrule.yaml @@ -0,0 +1,175 @@ +{{- if .Values.policies.include }} +apiVersion: neuvector.com/v1 +kind: NvSecurityRule +metadata: + name: nv.revproxy-deployment.{{ .Release.Namespace }} +spec: + dlp: + settings: [] + status: true + egress: + - action: allow + applications: + - DNS + name: nv.kube-dns.kube-system-egress-35 + ports: any + priority: 0 + selector: + comment: "" + criteria: + - key: service + op: = + value: kube-dns.kube-system + - key: domain + op: = + value: kube-system + name: nv.kube-dns.kube-system + original_name: "" + - action: allow + applications: + - HTTP + name: nv.sheepdog-deployment.{{ .Release.Namespace }}-egress-36 + ports: any + priority: 0 + selector: + comment: "" + criteria: + - key: service + op: = + value: sheepdog-deployment.{{ .Release.Namespace }} + - key: domain + op: = + value: {{ .Release.Namespace }} + name: nv.sheepdog-deployment.{{ .Release.Namespace }} + original_name: "" + file: [] + ingress: + - action: allow + applications: + - any + name: nv.revproxy-deployment.{{ .Release.Namespace }}-ingress-68 + ports: tcp/80,tcp/443 + priority: 0 + selector: + comment: "" + criteria: + - key: service + op: = + value: {{ .Values.ingress.controller }}.{{ .Values.ingress.namespace }} + - key: domain + op: = + value: {{ .Values.ingress.class }} + name: nv.{{ .Values.ingress.controller }}.{{ .Values.ingress.namespace }} + original_name: "" + - action: allow + applications: + - HTTP + name: nv.revproxy-deployment.{{ .Release.Namespace }}-ingress-69 + ports: any + priority: 0 + selector: + comment: "" + name: Workload:ingress + original_name: "" + - action: allow + applications: + - HTTP + name: nv.revproxy-deployment.{{ .Release.Namespace }}-ingress-70 + ports: any + priority: 0 + selector: + comment: "" + criteria: + - key: service + op: = + value: {{ .Values.ingress.controller }}.{{ .Values.ingress.namespace }} + - key: domain + op: = + value: {{ .Values.ingress.class }} + name: nv.{{ .Values.ingress.controller }}.{{ .Values.ingress.namespace }} + original_name: "" + - action: allow + applications: + - SSL + name: nv.revproxy-deployment.{{ .Release.Namespace }}-ingress-71 + ports: any + priority: 0 + selector: + comment: "" + criteria: [] + name: external + original_name: "" + - action: allow + applications: + - SSL + name: nv.revproxy-deployment.{{ .Release.Namespace }}-ingress-72 + ports: any + priority: 0 + selector: + comment: "" + criteria: + - key: service + op: = + value: sheepdog-deployment.{{ .Release.Namespace }} + - key: domain + op: = + value: {{ .Release.Namespace }} + name: nv.sheepdog-deployment.{{ .Release.Namespace }} + original_name: "" + - action: allow + applications: + - SSL + name: nv.revproxy-deployment.{{ .Release.Namespace }}-ingress-73 + ports: any + priority: 0 + selector: + comment: "" + criteria: + - key: service + op: = + value: cert-manager.cert-manager + - key: domain + op: = + value: cert-manager + name: nv.cert-manager.cert-manager + original_name: "" + process: + - action: allow + allow_update: false + name: bash + path: /bin/bash + - action: allow + allow_update: false + name: curl + path: /usr/bin/curl + - action: allow + allow_update: false + name: nginx + path: /usr/sbin/nginx + - action: allow + allow_update: false + name: pause + path: /pause + - action: allow + allow_update: false + name: sh + path: /bin/dash + process_profile: + baseline: zero-drift + target: + policymode: {{ .Values.policies.policyMode }} + selector: + comment: "" + criteria: + - key: service + op: = + value: revproxy-deployment.{{ .Release.Namespace }} + - key: domain + op: = + value: {{ .Release.Namespace }} + name: nv.revproxy-deployment.{{ .Release.Namespace }} + original_name: "" + waf: + settings: [] + status: true +{{- end }} \ No newline at end of file diff --git a/helm/neuvector/templates/sheepdog-nvsecurityrule.yaml b/helm/neuvector/templates/sheepdog-nvsecurityrule.yaml new file mode 100644 index 00000000..d587e45a --- /dev/null +++ b/helm/neuvector/templates/sheepdog-nvsecurityrule.yaml @@ -0,0 +1,184 @@ +{{- if .Values.policies.include }} +apiVersion: neuvector.com/v1 +kind: NvSecurityRule +metadata: + name: nv.sheepdog-deployment.{{ .Release.Namespace }} +spec: + dlp: + settings: [] + status: true + egress: + - action: allow + applications: + - DNS + name: nv.kube-dns.kube-system-egress-37 + ports: any + priority: 0 + selector: + comment: "" + criteria: + - key: service + op: = + value: kube-dns.kube-system + - key: domain + op: = + value: kube-system + name: nv.kube-dns.kube-system + original_name: "" + - action: allow + applications: + - HTTP + - SSL + name: external-egress-38 + ports: any + priority: 0 + selector: + comment: "" + criteria: [] + name: external + original_name: "" + - action: allow + applications: + - HTTP + - SSL + name: nv.{{ .Values.ingress.controller }}.{{ .Values.ingress.namespace }}-egress-39 + ports: any + priority: 0 + selector: + comment: "" + criteria: + - key: service + op: = + value: {{ .Values.ingress.controller }}.{{ .Values.ingress.namespace }} + - key: domain + op: = + value: {{ .Values.ingress.class }} + name: nv.{{ .Values.ingress.controller }}.{{ .Values.ingress.namespace }} + original_name: "" + file: [] + ingress: + - action: allow + applications: + - HTTP + name: nv.sheepdog-deployment.{{ .Release.Namespace }}-ingress-74 + ports: any + priority: 0 + selector: + comment: "" + name: Workload:ingress + original_name: "" + - action: allow + applications: + - SSL + name: nv.sheepdog-deployment.{{ .Release.Namespace }}-ingress-75 + ports: any + priority: 0 + selector: + comment: "" + criteria: [] + name: external + original_name: "" + process: + - action: allow + allow_update: false + name: basename + path: /usr/bin/basename + - action: allow + allow_update: false + name: bash + path: /bin/bash + - action: allow + allow_update: false + name: chmod + path: /bin/chmod + - action: allow + allow_update: false + name: dockerrun.sh + path: /bin/dash + - action: allow + allow_update: false + name: find + path: /usr/bin/find + - action: allow + allow_update: false + name: ldconfig + path: /sbin/ldconfig + - action: allow + allow_update: false + name: mkdir + path: /bin/mkdir + - action: allow + allow_update: false + name: mv + path: /bin/mv + - action: allow + allow_update: false + name: nginx + path: /usr/sbin/nginx + - action: allow + allow_update: false + name: pause + path: /pause + - action: allow + allow_update: false + name: python + path: /usr/local/bin/python3.6 + - action: allow + allow_update: false + name: python3 + path: /usr/local/bin/python3.6 + - action: allow + allow_update: false + name: readlink + path: /bin/readlink + - action: allow + allow_update: false + name: rm + path: /bin/rm + - action: allow + allow_update: false + name: run-parts + path: /bin/run-parts + - action: allow + allow_update: false + name: sed + path: /bin/sed + - action: allow + allow_update: false + name: sh + path: /bin/dash + - action: allow + allow_update: false + name: sort + path: /usr/bin/sort + - action: allow + allow_update: false + name: uname + path: /bin/uname + - action: allow + allow_update: false + name: uwsgi + path: /usr/local/bin/uwsgi + - action: allow + allow_update: false + name: wc + path: /usr/bin/wc + process_profile: + baseline: zero-drift + target: + policymode: {{ .Values.policies.policyMode }} + selector: + comment: "" + criteria: + - key: service + op: = + value: sheepdog-deployment.{{ .Release.Namespace }} + - key: domain + op: = + value: {{ .Release.Namespace }} + name: nv.sheepdog-deployment.{{ .Release.Namespace }} + original_name: "" + waf: + settings: [] + status: true +{{- end }} \ No newline at end of file diff --git a/helm/neuvector/templates/sower-nvsecurityrule.yaml b/helm/neuvector/templates/sower-nvsecurityrule.yaml new file mode 100644 index 00000000..fac23984 --- /dev/null +++ b/helm/neuvector/templates/sower-nvsecurityrule.yaml @@ -0,0 +1,32 @@ +{{- if .Values.policies.include }} +apiVersion: neuvector.com/v1 +kind: NvSecurityRule +metadata: + name: nv.sower.{{ .Release.Namespace }} +spec: + dlp: + settings: [] + status: true + egress: [] + file: [] + ingress: [] + process: [] + process_profile: + baseline: zero-drift + target: + policymode: {{ .Values.policies.policyMode }} + selector: + comment: "" + criteria: + - key: service + op: = + value: sower.{{ .Release.Namespace }} + - key: domain + op: = + value: {{ .Release.Namespace }} + name: nv.sower.{{ .Release.Namespace }} + original_name: "" + waf: + settings: [] + status: true +{{- end }} \ No newline at end of file diff --git a/helm/neuvector/templates/wts-nvsecurityrule.yaml b/helm/neuvector/templates/wts-nvsecurityrule.yaml new file mode 100644 index 00000000..de07659a --- /dev/null +++ b/helm/neuvector/templates/wts-nvsecurityrule.yaml @@ -0,0 +1,199 @@ +{{- if .Values.policies.include }} +apiVersion: neuvector.com/v1 +kind: NvSecurityRule +metadata: + name: nv.wts-deployment.{{ .Release.Namespace }} +spec: + dlp: + settings: [] + status: true + egress: + - action: allow + applications: + - DNS + name: nv.kube-dns.kube-system-egress-2 + ports: any + priority: 0 + selector: + comment: "" + criteria: + - key: service + op: = + value: kube-dns.kube-system + - key: domain + op: = + value: kube-system + name: nv.kube-dns.kube-system + original_name: "" + - action: allow + applications: + - HTTP + name: nv.fence-deployment.{{ .Release.Namespace }}-egress-3 + ports: any + priority: 0 + selector: + comment: "" + criteria: + - key: service + op: = + value: fence-deployment.{{ .Release.Namespace }} + - key: domain + op: = + value: {{ .Release.Namespace }} + name: nv.fence-deployment.{{ .Release.Namespace }} + original_name: "" + - action: allow + applications: + - PostgreSQL + name: nv.{{ .Values.DB_HOST }}.{{ .Release.Namespace }}-egress-4 + ports: any + priority: 0 + selector: + comment: "" + criteria: + - key: service + op: = + value: {{ .Values.DB_HOST }}.{{ .Release.Namespace }} + - key: domain + op: = + value: {{ .Release.Namespace }} + name: nv.{{ .Values.DB_HOST }}.{{ .Release.Namespace }} + original_name: "" + file: [] + ingress: + - action: allow + applications: + - any + name: nv.wts-deployment.{{ .Release.Namespace }}-ingress-11 + ports: tcp/80 + priority: 0 + selector: + comment: "" + name: Workload:ingress + original_name: "" + - action: allow + applications: + - SSL + name: nv.wts-deployment.{{ .Release.Namespace }}-ingress-12 + ports: any + priority: 0 + selector: + comment: "" + criteria: [] + name: external + original_name: "" + - action: allow + applications: + - HTTP + name: nv.wts-deployment.{{ .Release.Namespace }}-ingress-13 + ports: any + priority: 0 + selector: + comment: "" + criteria: + - key: service + op: = + value: revproxy-deployment.{{ .Release.Namespace }} + - key: domain + op: = + value: {{ .Release.Namespace }} + name: nv.revproxy-deployment.{{ .Release.Namespace }} + original_name: "" + - action: allow + applications: + - HTTP + name: nv.wts-deployment.{{ .Release.Namespace }}-ingress-14 + ports: any + priority: 0 + selector: + comment: "" + name: Workload:ingress + original_name: "" + process: + - action: allow + allow_update: false + name: alembic + path: /usr/local/bin/python3.9 + - action: allow + allow_update: false + name: basename + path: /usr/bin/basename + - action: allow + allow_update: false + name: chmod + path: /bin/chmod + - action: allow + allow_update: false + name: dockerrun.sh + path: /bin/dash + - action: allow + allow_update: false + name: find + path: /usr/bin/find + - action: allow + allow_update: false + name: mkdir + path: /bin/mkdir + - action: allow + allow_update: false + name: mv + path: /bin/mv + - action: allow + allow_update: false + name: nginx + path: /usr/sbin/nginx + - action: allow + allow_update: false + name: pause + path: /pause + - action: allow + allow_update: false + name: readlink + path: /bin/readlink + - action: allow + allow_update: false + name: rm + path: /bin/rm + - action: allow + allow_update: false + name: run-parts + path: /bin/run-parts + - action: allow + allow_update: false + name: sed + path: /bin/sed + - action: allow + allow_update: false + name: sh + path: /bin/dash + - action: allow + allow_update: false + name: sort + path: /usr/bin/sort + - action: allow + allow_update: false + name: uwsgi + path: /usr/local/bin/uwsgi + - action: allow + allow_update: false + name: wc + path: /usr/bin/wc + process_profile: + baseline: zero-drift + target: + policymode: {{ .Values.policies.policyMode }} + selector: + comment: "" + criteria: + - key: service + op: = + value: wts-deployment.{{ .Release.Namespace }} + - key: domain + op: = + value: {{ .Release.Namespace }} + name: nv.wts-deployment.{{ .Release.Namespace }} + original_name: "" + waf: + settings: [] + status: true +{{- end }} \ No newline at end of file diff --git a/helm/neuvector/values.yaml b/helm/neuvector/values.yaml new file mode 100644 index 00000000..410689cd --- /dev/null +++ b/helm/neuvector/values.yaml @@ -0,0 +1,32 @@ +# Default values for neuvector. +# This is a YAML-formatted file. +# Declare variables to be passed into your templates. + +nameOverride: "" +fullnameOverride: "" + +policies: + # deploy predefined Neuvector policies for Gen3 + include: true + # Neuvector policy enforcement mode + # Discover, Monitor, or Protect + # dev: Monitor + # prod: Protect + policyMode: Monitor + +# hostname/service name for our DB +DB_HOST: development-gen3-postgresql +# hostname/service name for our ElasitcSearch instance +ES_HOST: gen3-elasticsearch-master + +# Prefix for relevant services deployed through Argo +ARGOCD_PREFIX: development-gen3 + +# Configure your ingress controller information for enabling ingress to containers +ingress: + # service name of your ingress controller + controller: nginx-ingress-controller + # installation namespace of your ingress controller + namespace: nginx + # classname of your ingress + class: nginx diff --git a/helm/peregrine/Chart.yaml b/helm/peregrine/Chart.yaml index 6fea8732..10f79b5d 100644 --- a/helm/peregrine/Chart.yaml +++ b/helm/peregrine/Chart.yaml @@ -15,18 +15,18 @@ type: application # This is the chart version. This version number should be incremented each time you make changes # to the chart and its templates, including the app version. # Versions are expected to follow Semantic Versioning (https://semver.org/) -version: 0.1.10 +version: 0.1.13 # This is the version number of the application being deployed. This version number should be # incremented each time you make changes to the application. Versions are not expected to # follow Semantic Versioning. They should reflect the version the application is using. # It is recommended to use it with quotes. -appVersion: "2023.01" +appVersion: "master" dependencies: - name: common - version: 0.1.8 + version: 0.1.10 repository: file://../common - name: postgresql version: 11.9.13 diff --git a/helm/peregrine/README.md b/helm/peregrine/README.md index 42287fa9..12776689 100644 --- a/helm/peregrine/README.md +++ b/helm/peregrine/README.md @@ -1,6 +1,6 @@ # peregrine -![Version: 0.1.10](https://img.shields.io/badge/Version-0.1.10-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: 2023.01](https://img.shields.io/badge/AppVersion-2023.01-informational?style=flat-square) +![Version: 0.1.13](https://img.shields.io/badge/Version-0.1.13-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: master](https://img.shields.io/badge/AppVersion-master-informational?style=flat-square) A Helm chart for gen3 Peregrine service @@ -8,7 +8,7 @@ A Helm chart for gen3 Peregrine service | Repository | Name | Version | |------------|------|---------| -| file://../common | common | 0.1.8 | +| file://../common | common | 0.1.10 | | https://charts.bitnami.com/bitnami | postgresql | 11.9.13 | ## Values @@ -28,8 +28,9 @@ A Helm chart for gen3 Peregrine service | datadogProfilingEnabled | bool | `true` | If enabled, the Datadog Agent will collect profiling data for your application using the Continuous Profiler. This data can be used to identify performance bottlenecks and optimize your application. | | datadogTraceSampleRate | int | `1` | A value between 0 and 1, that represents the percentage of requests that will be traced. For example, a value of 0.5 means that 50% of requests will be traced. | | env | list | `nil` | Environment variables to pass to the container | +| externalSecrets | map | `{"dbcreds":null}` | External Secrets settings. | +| externalSecrets.dbcreds | string | `nil` | Will override the name of the aws secrets manager secret. Default is "Values.global.environment-.Chart.Name-creds" | | fullnameOverride | string | `""` | Override the full name of the deployment. | -| global | map | `{"aws":{"awsAccessKeyId":null,"awsSecretAccessKey":null,"enabled":false},"ddEnabled":false,"dev":true,"dictionaryUrl":"https://s3.amazonaws.com/dictionary-artifacts/datadictionary/develop/schema.json","dispatcherJobNum":10,"environment":"default","hostname":"localhost","kubeBucket":"kube-gen3","logsBucket":"logs-gen3","minAvialable":1,"netPolicy":true,"pdb":false,"portalApp":"gitops","postgres":{"dbCreate":true,"master":{"host":null,"password":null,"port":"5432","username":"postgres"}},"revproxyArn":"arn:aws:acm:us-east-1:123456:certificate","tierAccessLevel":"libre"}` | Global configuration options. | | global.aws | map | `{"awsAccessKeyId":null,"awsSecretAccessKey":null,"enabled":false}` | AWS configuration | | global.aws.awsAccessKeyId | string | `nil` | Credentials for AWS stuff. | | global.aws.awsSecretAccessKey | string | `nil` | Credentials for AWS stuff. | @@ -37,8 +38,11 @@ A Helm chart for gen3 Peregrine service | global.ddEnabled | bool | `false` | Whether Datadog is enabled. | | global.dev | bool | `true` | Whether the deployment is for development purposes. | | global.dictionaryUrl | string | `"https://s3.amazonaws.com/dictionary-artifacts/datadictionary/develop/schema.json"` | URL of the data dictionary. | -| global.dispatcherJobNum | int | `10` | Number of dispatcher jobs. | +| global.dispatcherJobNum | int | `"10"` | Number of dispatcher jobs. | | global.environment | string | `"default"` | Environment name. This should be the same as vpcname if you're doing an AWS deployment. Currently this is being used to share ALB's if you have multiple namespaces. Might be used other places too. | +| global.externalSecrets | map | `{"deploy":false,"separateSecretStore":false}` | External Secrets settings. | +| global.externalSecrets.deploy | bool | `false` | Will use ExternalSecret resources to pull secrets from Secrets Manager instead of creating them locally. Be cautious as this will override any peregrine secrets you have deployed. | +| global.externalSecrets.separateSecretStore | string | `false` | Will deploy a separate External Secret Store for this service. | | global.hostname | string | `"localhost"` | Hostname for the deployment. | | global.kubeBucket | string | `"kube-gen3"` | S3 bucket name for Kubernetes manifest files. | | global.logsBucket | string | `"logs-gen3"` | S3 bucket name for log files. | @@ -46,8 +50,8 @@ A Helm chart for gen3 Peregrine service | global.netPolicy | bool | `true` | Whether network policies are enabled. | | global.pdb | bool | `false` | If the service will be deployed with a Pod Disruption Budget. Note- you need to have more than 2 replicas for the pdb to be deployed. | | global.portalApp | string | `"gitops"` | Portal application name. | -| global.postgres | map | `{"dbCreate":true,"master":{"host":null,"password":null,"port":"5432","username":"postgres"}}` | Postgres database configuration. | | global.postgres.dbCreate | bool | `true` | Whether the database should be created. | +| global.postgres.externalSecret | string | `""` | Name of external secret. Disabled if empty | | global.postgres.master | map | `{"host":null,"password":null,"port":"5432","username":"postgres"}` | Master credentials to postgres. This is going to be the default postgres server being used for each service, unless each service specifies their own postgres | | global.postgres.master.host | string | `nil` | hostname of postgres server | | global.postgres.master.password | string | `nil` | password for superuser in postgres. This is used to create or restore databases | @@ -57,7 +61,7 @@ A Helm chart for gen3 Peregrine service | global.tierAccessLevel | string | `"libre"` | Access level for tiers. acceptable values for `tier_access_level` are: `libre`, `regular` and `private`. If omitted, by default common will be treated as `private` | | image.pullPolicy | string | `"IfNotPresent"` | When to pull the image. | | image.repository | string | `"quay.io/cdis/peregrine"` | The Docker image repository for the fence service | -| image.tag | string | `""` | Overrides the image tag whose default is the chart appVersion. | +| image.tag | string | `"feat_jq-audience"` | Overrides the image tag whose default is the chart appVersion. | | imagePullSecrets | list | `[]` | Docker image pull secrets. | | nameOverride | string | `""` | Override the name of the chart. | | nodeSelector | map | `{}` | Node Selector for the pods | @@ -82,6 +86,9 @@ A Helm chart for gen3 Peregrine service | resources.requests | map | `{"cpu":0.1,"memory":"12Mi"}` | The amount of resources that the container requests | | resources.requests.cpu | string | `0.1` | The amount of CPU requested | | resources.requests.memory | string | `"12Mi"` | The amount of memory requested | +| secrets | map | `{"awsAccessKeyId":null,"awsSecretAccessKey":null}` | Secret information for External Secrets. | +| secrets.awsAccessKeyId | str | `nil` | AWS access key ID. Overrides global key. | +| secrets.awsSecretAccessKey | str | `nil` | AWS secret access key ID. Overrides global key. | | securityContext | map | `{}` | Security context for the containers in the pod | | selectorLabels | map | `nil` | Will completely override the selectorLabels defined in the common chart's _label_setup.tpl | | service | map | `{"port":80,"type":"ClusterIP"}` | Kubernetes service information. | @@ -99,5 +106,3 @@ A Helm chart for gen3 Peregrine service | volumeMounts | list | `[{"mountPath":"/peregrine/deployment/wsgi/wsgi.py","name":"config-volume","readOnly":true,"subPath":"settings.py"},{"mountPath":"/peregrine/deployment/wsgi/gunicorn.conf.py","name":"wsgi-config","subPath":"gunicorn.conf.py"}]` | Volumes to mount to the container. | | volumes | list | `[{"emptyDir":{},"name":"shared-data"},{"name":"config-volume","secret":{"secretName":"peregrine-secret"}},{"configMap":{"name":"peregrine-wsgi"},"name":"wsgi-config"},{"configMap":{"name":"peregrine-nginx-configmap"},"name":"nginx-config"}]` | Volumes to attach to the container. | ----------------------------------------------- -Autogenerated from chart metadata using [helm-docs v1.11.0](https://github.com/norwoodj/helm-docs/releases/v1.11.0) diff --git a/helm/peregrine/templates/_helpers.tpl b/helm/peregrine/templates/_helpers.tpl index 1674a02f..4d1439e0 100644 --- a/helm/peregrine/templates/_helpers.tpl +++ b/helm/peregrine/templates/_helpers.tpl @@ -90,4 +90,4 @@ Define dictionaryUrl {{- else}} {{- .Values.dictionaryUrl }} {{- end }} -{{- end }} \ No newline at end of file +{{- end }} diff --git a/helm/peregrine/templates/aws-config.yaml b/helm/peregrine/templates/aws-config.yaml new file mode 100644 index 00000000..398770d3 --- /dev/null +++ b/helm/peregrine/templates/aws-config.yaml @@ -0,0 +1,3 @@ +{{- if or (.Values.secrets.awsSecretAccessKey) (.Values.global.aws.awsSecretAccessKey ) }} +{{ include "common.awsconfig" . }} +{{- end -}} \ No newline at end of file diff --git a/helm/peregrine/templates/db-init.yaml b/helm/peregrine/templates/db-init.yaml index abbefb6e..5ef14e87 100644 --- a/helm/peregrine/templates/db-init.yaml +++ b/helm/peregrine/templates/db-init.yaml @@ -1,6 +1,6 @@ -{{ include "common.db_setup_job" . }} ---- {{ include "common.db-secret" . }} --- -{{ include "common.db_setup_sa" . }} +{{ include "common.db_setup_job" . }} --- +{{ include "common.db_setup_sa" . }} +--- \ No newline at end of file diff --git a/helm/peregrine/templates/deployment.yaml b/helm/peregrine/templates/deployment.yaml index a661b8a0..9d9cc66e 100644 --- a/helm/peregrine/templates/deployment.yaml +++ b/helm/peregrine/templates/deployment.yaml @@ -154,7 +154,7 @@ spec: {{- with .Values.volumeMounts }} volumeMounts: {{- toYaml . | nindent 10 }} - {{- end }} + {{- end }} ports: - containerPort: 8000 livenessProbe: diff --git a/helm/peregrine/templates/external-secret.yaml b/helm/peregrine/templates/external-secret.yaml new file mode 100644 index 00000000..70c278fe --- /dev/null +++ b/helm/peregrine/templates/external-secret.yaml @@ -0,0 +1 @@ +{{ include "common.externalSecret.db" . }} \ No newline at end of file diff --git a/helm/peregrine/templates/secret-store.yaml b/helm/peregrine/templates/secret-store.yaml new file mode 100644 index 00000000..771c7760 --- /dev/null +++ b/helm/peregrine/templates/secret-store.yaml @@ -0,0 +1,3 @@ +{{ if .Values.global.externalSecrets.separateSecretStore }} +{{ include "common.secretstore" . }} +{{- end }} \ No newline at end of file diff --git a/helm/peregrine/values.yaml b/helm/peregrine/values.yaml index 83dd3546..39acc7a0 100644 --- a/helm/peregrine/values.yaml +++ b/helm/peregrine/values.yaml @@ -1,7 +1,8 @@ # Default values for peregrine. # This is a YAML-formatted file. -# -- (map) Global configuration options. + +# Global configuration global: # -- (map) AWS configuration aws: @@ -13,10 +14,12 @@ global: awsSecretAccessKey: # -- (bool) Whether the deployment is for development purposes. dev: true - # -- (map) Postgres database configuration. + postgres: # -- (bool) Whether the database should be created. dbCreate: true + # -- (string) Name of external secret. Disabled if empty + externalSecret: "" # -- (map) Master credentials to postgres. This is going to be the default postgres server being used for each service, unless each service specifies their own postgres master: # -- (string) hostname of postgres server @@ -46,13 +49,31 @@ global: # -- (bool) Whether network policies are enabled. netPolicy: true # -- (int) Number of dispatcher jobs. - dispatcherJobNum: 10 + dispatcherJobNum: "10" # -- (bool) Whether Datadog is enabled. ddEnabled: false # -- (bool) If the service will be deployed with a Pod Disruption Budget. Note- you need to have more than 2 replicas for the pdb to be deployed. pdb: false # -- (int) The minimum amount of pods that are available at all times if the PDB is deployed. minAvialable: 1 + # -- (map) External Secrets settings. + externalSecrets: + # -- (bool) Will use ExternalSecret resources to pull secrets from Secrets Manager instead of creating them locally. Be cautious as this will override any peregrine secrets you have deployed. + deploy: false + # -- (string) Will deploy a separate External Secret Store for this service. + separateSecretStore: false + +# -- (map) External Secrets settings. +externalSecrets: + # -- (string) Will override the name of the aws secrets manager secret. Default is "Values.global.environment-.Chart.Name-creds" + dbcreds: +# -- (map) Secret information for External Secrets. +secrets: + # -- (str) AWS access key ID. Overrides global key. + awsAccessKeyId: + # -- (str) AWS secret access key ID. Overrides global key. + awsSecretAccessKey: + # -- (map) Postgres database configuration. If db does not exist in postgres cluster and dbCreate is set ot true then these databases will be created for you postgres: @@ -92,7 +113,7 @@ image: # -- (string) When to pull the image. pullPolicy: IfNotPresent # -- (string) Overrides the image tag whose default is the chart appVersion. - tag: "" + tag: "feat_jq-audience" # -- (map) Configuration for Nginx sidecar container to be deployed with gunicorn. sidecar: diff --git a/helm/pidgin/Chart.yaml b/helm/pidgin/Chart.yaml index c871f126..be9c2086 100644 --- a/helm/pidgin/Chart.yaml +++ b/helm/pidgin/Chart.yaml @@ -15,7 +15,7 @@ type: application # This is the chart version. This version number should be incremented each time you make changes # to the chart and its templates, including the app version. # Versions are expected to follow Semantic Versioning (https://semver.org/) -version: 0.1.8 +version: 0.1.10 # This is the version number of the application being deployed. This version number should be # incremented each time you make changes to the application. Versions are not expected to @@ -25,5 +25,5 @@ appVersion: "master" dependencies: - name: common - version: 0.1.8 + version: 0.1.10 repository: file://../common diff --git a/helm/pidgin/README.md b/helm/pidgin/README.md index 72b5f9bc..21914338 100644 --- a/helm/pidgin/README.md +++ b/helm/pidgin/README.md @@ -1,6 +1,6 @@ # pidgin -![Version: 0.1.8](https://img.shields.io/badge/Version-0.1.8-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: master](https://img.shields.io/badge/AppVersion-master-informational?style=flat-square) +![Version: 0.1.10](https://img.shields.io/badge/Version-0.1.10-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: master](https://img.shields.io/badge/AppVersion-master-informational?style=flat-square) A Helm chart for gen3 Pidgin Service @@ -8,7 +8,7 @@ A Helm chart for gen3 Pidgin Service | Repository | Name | Version | |------------|------|---------| -| file://../common | common | 0.1.8 | +| file://../common | common | 0.1.10 | ## Values @@ -33,7 +33,6 @@ A Helm chart for gen3 Pidgin Service | datadogLogsInjection | bool | `true` | If enabled, the Datadog Agent will automatically inject Datadog-specific metadata into your application logs. | | datadogProfilingEnabled | bool | `true` | If enabled, the Datadog Agent will collect profiling data for your application using the Continuous Profiler. This data can be used to identify performance bottlenecks and optimize your application. | | datadogTraceSampleRate | int | `1` | A value between 0 and 1, that represents the percentage of requests that will be traced. For example, a value of 0.5 means that 50% of requests will be traced. | -| global | map | `{"aws":{"awsAccessKeyId":null,"awsSecretAccessKey":null,"enabled":false},"ddEnabled":false,"dev":true,"dictionaryUrl":"https://s3.amazonaws.com/dictionary-artifacts/datadictionary/develop/schema.json","dispatcherJobNum":10,"environment":"default","hostname":"localhost","kubeBucket":"kube-gen3","logsBucket":"logs-gen3","minAvialable":1,"netPolicy":true,"pdb":false,"portalApp":"gitops","postgres":{"dbCreate":true,"master":{"host":null,"password":null,"port":"5432","username":"postgres"}},"publicDataSets":true,"revproxyArn":"arn:aws:acm:us-east-1:123456:certificate","tierAccessLevel":"libre"}` | Global configuration options. | | global.aws | map | `{"awsAccessKeyId":null,"awsSecretAccessKey":null,"enabled":false}` | AWS configuration | | global.aws.awsAccessKeyId | string | `nil` | Credentials for AWS stuff. | | global.aws.awsSecretAccessKey | string | `nil` | Credentials for AWS stuff. | @@ -41,7 +40,7 @@ A Helm chart for gen3 Pidgin Service | global.ddEnabled | bool | `false` | Whether Datadog is enabled. | | global.dev | bool | `true` | Whether the deployment is for development purposes. | | global.dictionaryUrl | string | `"https://s3.amazonaws.com/dictionary-artifacts/datadictionary/develop/schema.json"` | URL of the data dictionary. | -| global.dispatcherJobNum | int | `10` | Number of dispatcher jobs. | +| global.dispatcherJobNum | int | `"10"` | Number of dispatcher jobs. | | global.environment | string | `"default"` | Environment name. This should be the same as vpcname if you're doing an AWS deployment. Currently this is being used to share ALB's if you have multiple namespaces. Might be used other places too. | | global.hostname | string | `"localhost"` | Hostname for the deployment. | | global.kubeBucket | string | `"kube-gen3"` | S3 bucket name for Kubernetes manifest files. | @@ -50,8 +49,8 @@ A Helm chart for gen3 Pidgin Service | global.netPolicy | bool | `true` | Whether network policies are enabled. | | global.pdb | bool | `false` | If the service will be deployed with a Pod Disruption Budget. Note- you need to have more than 2 replicas for the pdb to be deployed. | | global.portalApp | string | `"gitops"` | Portal application name. | -| global.postgres | map | `{"dbCreate":true,"master":{"host":null,"password":null,"port":"5432","username":"postgres"}}` | Postgres database configuration. | | global.postgres.dbCreate | bool | `true` | Whether the database should be created. | +| global.postgres.externalSecret | string | `""` | Name of external secret. Disabled if empty | | global.postgres.master | map | `{"host":null,"password":null,"port":"5432","username":"postgres"}` | Master credentials to postgres. This is going to be the default postgres server being used for each service, unless each service specifies their own postgres | | global.postgres.master.host | string | `nil` | hostname of postgres server | | global.postgres.master.password | string | `nil` | password for superuser in postgres. This is used to create or restore databases | @@ -83,5 +82,3 @@ A Helm chart for gen3 Pidgin Service | strategy.rollingUpdate.maxSurge | int | `1` | Number of additional replicas to add during rollout. | | strategy.rollingUpdate.maxUnavailable | int | `0` | Maximum amount of pods that can be unavailable during the update. | ----------------------------------------------- -Autogenerated from chart metadata using [helm-docs v1.11.0](https://github.com/norwoodj/helm-docs/releases/v1.11.0) diff --git a/helm/pidgin/values.yaml b/helm/pidgin/values.yaml index fb683716..414d642b 100644 --- a/helm/pidgin/values.yaml +++ b/helm/pidgin/values.yaml @@ -2,7 +2,8 @@ # This is a YAML-formatted file. # Declare variables to be passed into your templates. -# -- (map) Global configuration options. + +# Global configuration global: # -- (map) AWS configuration aws: @@ -14,10 +15,12 @@ global: awsSecretAccessKey: # -- (bool) Whether the deployment is for development purposes. dev: true - # -- (map) Postgres database configuration. + postgres: # -- (bool) Whether the database should be created. dbCreate: true + # -- (string) Name of external secret. Disabled if empty + externalSecret: "" # -- (map) Master credentials to postgres. This is going to be the default postgres server being used for each service, unless each service specifies their own postgres master: # -- (string) hostname of postgres server @@ -49,7 +52,7 @@ global: # -- (bool) Whether network policies are enabled. netPolicy: true # -- (int) Number of dispatcher jobs. - dispatcherJobNum: 10 + dispatcherJobNum: "10" # -- (bool) Whether Datadog is enabled. ddEnabled: false # -- (bool) If the service will be deployed with a Pod Disruption Budget. Note- you need to have more than 2 replicas for the pdb to be deployed. diff --git a/helm/portal/Chart.yaml b/helm/portal/Chart.yaml index 1a992152..6141c5e5 100644 --- a/helm/portal/Chart.yaml +++ b/helm/portal/Chart.yaml @@ -15,7 +15,7 @@ type: application # This is the chart version. This version number should be incremented each time you make changes # to the chart and its templates, including the app version. # Versions are expected to follow Semantic Versioning (https://semver.org/) -version: 0.1.8 +version: 0.1.15 # This is the version number of the application being deployed. This version number should be # incremented each time you make changes to the application. Versions are not expected to @@ -25,5 +25,5 @@ appVersion: "master" dependencies: - name: common - version: 0.1.8 + version: 0.1.10 repository: file://../common diff --git a/helm/portal/README.md b/helm/portal/README.md index 11381d2b..af2b96ea 100644 --- a/helm/portal/README.md +++ b/helm/portal/README.md @@ -1,6 +1,6 @@ # portal -![Version: 0.1.8](https://img.shields.io/badge/Version-0.1.8-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: master](https://img.shields.io/badge/AppVersion-master-informational?style=flat-square) +![Version: 0.1.15](https://img.shields.io/badge/Version-0.1.15-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: master](https://img.shields.io/badge/AppVersion-master-informational?style=flat-square) A Helm chart for gen3 data-portal @@ -8,7 +8,7 @@ A Helm chart for gen3 data-portal | Repository | Name | Version | |------------|------|---------| -| file://../common | common | 0.1.8 | +| file://../common | common | 0.1.10 | ## Values @@ -32,6 +32,7 @@ A Helm chart for gen3 data-portal | datadogLogsInjection | bool | `true` | If enabled, the Datadog Agent will automatically inject Datadog-specific metadata into your application logs. | | datadogProfilingEnabled | bool | `true` | If enabled, the Datadog Agent will collect profiling data for your application using the Continuous Profiler. This data can be used to identify performance bottlenecks and optimize your application. | | datadogTraceSampleRate | int | `1` | A value between 0 and 1, that represents the percentage of requests that will be traced. For example, a value of 0.5 means that 50% of requests will be traced. | +| extraImages | map | `nil` | Extra images to be mounted in the deployment. | | fullnameOverride | string | `""` | Override the full name of the deployment. | | gitops | map | `{"createdby":"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","css":"/* gitops default css */\n","favicon":"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","json":"{\n \"graphql\": {\n \"boardCounts\": [\n {\n \"graphql\": \"_case_count\",\n \"name\": \"Case\",\n \"plural\": \"Cases\"\n },\n {\n \"graphql\": \"_experiment_count\",\n \"name\": \"Experiment\",\n \"plural\": \"Experiments\"\n },\n {\n \"graphql\": \"_aliquot_count\",\n \"name\": \"Aliquot\",\n \"plural\": \"Aliquots\"\n }\n ],\n \"chartCounts\": [\n {\n \"graphql\": \"_case_count\",\n \"name\": \"Case\"\n },\n {\n \"graphql\": \"_experiment_count\",\n \"name\": \"Experiment\"\n },\n {\n \"graphql\": \"_aliquot_count\",\n \"name\": \"Aliquot\"\n }\n ],\n \"projectDetails\": \"boardCounts\"\n },\n \"components\": {\n \"appName\": \"Generic Data Commons Portal\",\n \"index\": {\n \"introduction\": {\n \"heading\": \"Data Commons\",\n \"text\": \"The Generic Data Commons supports the management, analysis and sharing of data for the research community.\",\n \"link\": \"/submission\"\n },\n \"buttons\": [\n {\n \"name\": \"Define Data Field\",\n \"icon\": \"data-field-define\",\n \"body\": \"The Generic Data Commons define the data in a general way. Please study the dictionary before you start browsing.\",\n \"link\": \"/DD\",\n \"label\": \"Learn more\"\n },\n {\n \"name\": \"Explore Data\",\n \"icon\": \"data-explore\",\n \"body\": \"The Exploration Page gives you insights and a clear overview under selected factors.\",\n \"link\": \"/explorer\",\n \"label\": \"Explore data\"\n },\n {\n \"name\": \"Access Data\",\n \"icon\": \"data-access\",\n \"body\": \"Use our selected tool to filter out the data you need.\",\n \"link\": \"/query\",\n \"label\": \"Query data\"\n },\n {\n \"name\": \"Submit Data\",\n \"icon\": \"data-submit\",\n \"body\": \"Submit Data based on the dictionary.\",\n \"link\": \"/submission\",\n \"label\": \"Submit data\"\n }\n ]\n },\n \"navigation\": {\n \"title\": \"Generic Data Commons\",\n \"items\": [\n {\n \"icon\": \"dictionary\",\n \"link\": \"/DD\",\n \"color\": \"#a2a2a2\",\n \"name\": \"Dictionary\"\n },\n {\n \"icon\": \"exploration\",\n \"link\": \"/explorer\",\n \"color\": \"#a2a2a2\",\n \"name\": \"Exploration\"\n },\n {\n \"icon\": \"query\",\n \"link\": \"/query\",\n \"color\": \"#a2a2a2\",\n \"name\": \"Query\"\n },\n {\n \"icon\": \"workspace\",\n \"link\": \"/workspace\",\n \"color\": \"#a2a2a2\",\n \"name\": \"Workspace\"\n },\n {\n \"icon\": \"profile\",\n \"link\": \"/identity\",\n \"color\": \"#a2a2a2\",\n \"name\": \"Profile\"\n }\n ]\n },\n \"topBar\": {\n \"items\": [\n {\n \"icon\": \"upload\",\n \"link\": \"/submission\",\n \"name\": \"Submit Data\"\n },\n {\n \"link\": \"https://gen3.org/resources/user\",\n \"name\": \"Documentation\"\n }\n ]\n },\n \"login\": {\n \"title\": \"Generic Data Commons\",\n \"subTitle\": \"Explore, Analyze, and Share Data\",\n \"text\": \"This website supports the management, analysis and sharing of human disease data for the research community and aims to advance basic understanding of the genetic basis of complex traits and accelerate discovery and development of therapies, diagnostic tests, and other technologies for diseases like cancer.\",\n \"contact\": \"If you have any questions about access or the registration process, please contact \",\n \"email\": \"support@datacommons.io\"\n },\n \"certs\": {},\n \"footerLogos\": [\n {\n \"src\": \"/src/img/gen3.png\",\n \"href\": \"https://ctds.uchicago.edu/gen3\",\n \"alt\": \"Gen3 Data Commons\"\n },\n {\n \"src\": \"/src/img/createdby.png\",\n \"href\": \"https://ctds.uchicago.edu/\",\n \"alt\": \"Center for Translational Data Science at the University of Chicago\"\n }\n ]\n },\n \"requiredCerts\": [],\n \"featureFlags\": {\n \"explorer\": true,\n \"noIndex\": true,\n \"analysis\": false,\n \"discovery\": false,\n \"discoveryUseAggMDS\": false,\n \"studyRegistration\": false\n },\n \"dataExplorerConfig\": {\n \"charts\": {\n \"project_id\": {\n \"chartType\": \"count\",\n \"title\": \"Projects\"\n },\n \"_case_id\": {\n \"chartType\": \"count\",\n \"title\": \"Cases\"\n },\n \"gender\": {\n \"chartType\": \"pie\",\n \"title\": \"Gender\"\n },\n \"race\": {\n \"chartType\": \"bar\",\n \"title\": \"Race\"\n }\n },\n \"filters\": {\n \"tabs\": [\n {\n \"title\": \"Case\",\n \"fields\":[\n \"project_id\",\n \"gender\",\n \"race\",\n \"ethnicity\"\n ]\n }\n ]\n },\n \"table\": {\n \"enabled\": false\n },\n \"dropdowns\": {},\n \"buttons\": [],\n \"guppyConfig\": {\n \"dataType\": \"case\",\n \"nodeCountTitle\": \"Cases\",\n \"fieldMapping\": [\n { \"field\": \"disease_type\", \"name\": \"Disease type\" },\n { \"field\": \"primary_site\", \"name\": \"Site where samples were collected\"}\n ],\n \"manifestMapping\": {\n \"resourceIndexType\": \"file\",\n \"resourceIdField\": \"object_id\",\n \"referenceIdFieldInResourceIndex\": \"_case_id\",\n \"referenceIdFieldInDataIndex\": \"node_id\"\n },\n \"accessibleFieldCheckList\": [\"_case_id\"],\n \"accessibleValidationField\": \"_case_id\"\n }\n },\n \"fileExplorerConfig\": {\n \"charts\": {\n \"data_type\": {\n \"chartType\": \"stackedBar\",\n \"title\": \"File Type\"\n },\n \"data_format\": {\n \"chartType\": \"stackedBar\",\n \"title\": \"File Format\"\n }\n },\n \"filters\": {\n \"tabs\": [\n {\n \"title\": \"File\",\n \"fields\": [\n \"project_id\",\n \"data_type\",\n \"data_format\"\n ]\n }\n ]\n },\n \"table\": {\n \"enabled\": true,\n \"fields\": [\n \"project_id\",\n \"file_name\",\n \"file_size\",\n \"object_id\"\n ]\n },\n \"dropdowns\": {},\n \"guppyConfig\": {\n \"dataType\": \"file\",\n \"fieldMapping\": [\n { \"field\": \"object_id\", \"name\": \"GUID\" }\n ],\n \"nodeCountTitle\": \"Files\",\n \"manifestMapping\": {\n \"resourceIndexType\": \"case\",\n \"resourceIdField\": \"_case_id\",\n \"referenceIdFieldInResourceIndex\": \"object_id\",\n \"referenceIdFieldInDataIndex\": \"object_id\"\n },\n \"accessibleFieldCheckList\": [\"_case_id\"],\n \"accessibleValidationField\": \"_case_id\",\n \"downloadAccessor\": \"object_id\"\n }\n }\n}\n","logo":"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","sponsors":null}` | GitOps configuration for portal | | gitops.createdby | string | `"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"` | - createdby.png - base64 | @@ -39,7 +40,6 @@ A Helm chart for gen3 data-portal | gitops.favicon | string | `"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"` | - favicon in base64 | | gitops.json | string | `"{\n \"graphql\": {\n \"boardCounts\": [\n {\n \"graphql\": \"_case_count\",\n \"name\": \"Case\",\n \"plural\": \"Cases\"\n },\n {\n \"graphql\": \"_experiment_count\",\n \"name\": \"Experiment\",\n \"plural\": \"Experiments\"\n },\n {\n \"graphql\": \"_aliquot_count\",\n \"name\": \"Aliquot\",\n \"plural\": \"Aliquots\"\n }\n ],\n \"chartCounts\": [\n {\n \"graphql\": \"_case_count\",\n \"name\": \"Case\"\n },\n {\n \"graphql\": \"_experiment_count\",\n \"name\": \"Experiment\"\n },\n {\n \"graphql\": \"_aliquot_count\",\n \"name\": \"Aliquot\"\n }\n ],\n \"projectDetails\": \"boardCounts\"\n },\n \"components\": {\n \"appName\": \"Generic Data Commons Portal\",\n \"index\": {\n \"introduction\": {\n \"heading\": \"Data Commons\",\n \"text\": \"The Generic Data Commons supports the management, analysis and sharing of data for the research community.\",\n \"link\": \"/submission\"\n },\n \"buttons\": [\n {\n \"name\": \"Define Data Field\",\n \"icon\": \"data-field-define\",\n \"body\": \"The Generic Data Commons define the data in a general way. Please study the dictionary before you start browsing.\",\n \"link\": \"/DD\",\n \"label\": \"Learn more\"\n },\n {\n \"name\": \"Explore Data\",\n \"icon\": \"data-explore\",\n \"body\": \"The Exploration Page gives you insights and a clear overview under selected factors.\",\n \"link\": \"/explorer\",\n \"label\": \"Explore data\"\n },\n {\n \"name\": \"Access Data\",\n \"icon\": \"data-access\",\n \"body\": \"Use our selected tool to filter out the data you need.\",\n \"link\": \"/query\",\n \"label\": \"Query data\"\n },\n {\n \"name\": \"Submit Data\",\n \"icon\": \"data-submit\",\n \"body\": \"Submit Data based on the dictionary.\",\n \"link\": \"/submission\",\n \"label\": \"Submit data\"\n }\n ]\n },\n \"navigation\": {\n \"title\": \"Generic Data Commons\",\n \"items\": [\n {\n \"icon\": \"dictionary\",\n \"link\": \"/DD\",\n \"color\": \"#a2a2a2\",\n \"name\": \"Dictionary\"\n },\n {\n \"icon\": \"exploration\",\n \"link\": \"/explorer\",\n \"color\": \"#a2a2a2\",\n \"name\": \"Exploration\"\n },\n {\n \"icon\": \"query\",\n \"link\": \"/query\",\n \"color\": \"#a2a2a2\",\n \"name\": \"Query\"\n },\n {\n \"icon\": \"workspace\",\n \"link\": \"/workspace\",\n \"color\": \"#a2a2a2\",\n \"name\": \"Workspace\"\n },\n {\n \"icon\": \"profile\",\n \"link\": \"/identity\",\n \"color\": \"#a2a2a2\",\n \"name\": \"Profile\"\n }\n ]\n },\n \"topBar\": {\n \"items\": [\n {\n \"icon\": \"upload\",\n \"link\": \"/submission\",\n \"name\": \"Submit Data\"\n },\n {\n \"link\": \"https://gen3.org/resources/user\",\n \"name\": \"Documentation\"\n }\n ]\n },\n \"login\": {\n \"title\": \"Generic Data Commons\",\n \"subTitle\": \"Explore, Analyze, and Share Data\",\n \"text\": \"This website supports the management, analysis and sharing of human disease data for the research community and aims to advance basic understanding of the genetic basis of complex traits and accelerate discovery and development of therapies, diagnostic tests, and other technologies for diseases like cancer.\",\n \"contact\": \"If you have any questions about access or the registration process, please contact \",\n \"email\": \"support@datacommons.io\"\n },\n \"certs\": {},\n \"footerLogos\": [\n {\n \"src\": \"/src/img/gen3.png\",\n \"href\": \"https://ctds.uchicago.edu/gen3\",\n \"alt\": \"Gen3 Data Commons\"\n },\n {\n \"src\": \"/src/img/createdby.png\",\n \"href\": \"https://ctds.uchicago.edu/\",\n \"alt\": \"Center for Translational Data Science at the University of Chicago\"\n }\n ]\n },\n \"requiredCerts\": [],\n \"featureFlags\": {\n \"explorer\": true,\n \"noIndex\": true,\n \"analysis\": false,\n \"discovery\": false,\n \"discoveryUseAggMDS\": false,\n \"studyRegistration\": false\n },\n \"dataExplorerConfig\": {\n \"charts\": {\n \"project_id\": {\n \"chartType\": \"count\",\n \"title\": \"Projects\"\n },\n \"_case_id\": {\n \"chartType\": \"count\",\n \"title\": \"Cases\"\n },\n \"gender\": {\n \"chartType\": \"pie\",\n \"title\": \"Gender\"\n },\n \"race\": {\n \"chartType\": \"bar\",\n \"title\": \"Race\"\n }\n },\n \"filters\": {\n \"tabs\": [\n {\n \"title\": \"Case\",\n \"fields\":[\n \"project_id\",\n \"gender\",\n \"race\",\n \"ethnicity\"\n ]\n }\n ]\n },\n \"table\": {\n \"enabled\": false\n },\n \"dropdowns\": {},\n \"buttons\": [],\n \"guppyConfig\": {\n \"dataType\": \"case\",\n \"nodeCountTitle\": \"Cases\",\n \"fieldMapping\": [\n { \"field\": \"disease_type\", \"name\": \"Disease type\" },\n { \"field\": \"primary_site\", \"name\": \"Site where samples were collected\"}\n ],\n \"manifestMapping\": {\n \"resourceIndexType\": \"file\",\n \"resourceIdField\": \"object_id\",\n \"referenceIdFieldInResourceIndex\": \"_case_id\",\n \"referenceIdFieldInDataIndex\": \"node_id\"\n },\n \"accessibleFieldCheckList\": [\"_case_id\"],\n \"accessibleValidationField\": \"_case_id\"\n }\n },\n \"fileExplorerConfig\": {\n \"charts\": {\n \"data_type\": {\n \"chartType\": \"stackedBar\",\n \"title\": \"File Type\"\n },\n \"data_format\": {\n \"chartType\": \"stackedBar\",\n \"title\": \"File Format\"\n }\n },\n \"filters\": {\n \"tabs\": [\n {\n \"title\": \"File\",\n \"fields\": [\n \"project_id\",\n \"data_type\",\n \"data_format\"\n ]\n }\n ]\n },\n \"table\": {\n \"enabled\": true,\n \"fields\": [\n \"project_id\",\n \"file_name\",\n \"file_size\",\n \"object_id\"\n ]\n },\n \"dropdowns\": {},\n \"guppyConfig\": {\n \"dataType\": \"file\",\n \"fieldMapping\": [\n { \"field\": \"object_id\", \"name\": \"GUID\" }\n ],\n \"nodeCountTitle\": \"Files\",\n \"manifestMapping\": {\n \"resourceIndexType\": \"case\",\n \"resourceIdField\": \"_case_id\",\n \"referenceIdFieldInResourceIndex\": \"object_id\",\n \"referenceIdFieldInDataIndex\": \"object_id\"\n },\n \"accessibleFieldCheckList\": [\"_case_id\"],\n \"accessibleValidationField\": \"_case_id\",\n \"downloadAccessor\": \"object_id\"\n }\n }\n}\n"` | multiline string - gitops.json | | gitops.logo | string | `"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"` | - logo in base64 | -| global | map | `{"aws":{"awsAccessKeyId":null,"awsSecretAccessKey":null,"enabled":false},"ddEnabled":false,"dev":true,"dictionaryUrl":"https://s3.amazonaws.com/dictionary-artifacts/datadictionary/develop/schema.json","dispatcherJobNum":10,"environment":"default","hostname":"localhost","kubeBucket":"kube-gen3","logsBucket":"logs-gen3","minAvialable":1,"netPolicy":true,"pdb":false,"portalApp":"gitops","postgres":{"dbCreate":true,"master":{"host":null,"password":null,"port":"5432","username":"postgres"}},"publicDataSets":true,"revproxyArn":"arn:aws:acm:us-east-1:123456:certificate","tierAccessLevel":"libre","tierAccessLimit":1000}` | Global configuration options. | | global.aws | map | `{"awsAccessKeyId":null,"awsSecretAccessKey":null,"enabled":false}` | AWS configuration | | global.aws.awsAccessKeyId | string | `nil` | Credentials for AWS stuff. | | global.aws.awsSecretAccessKey | string | `nil` | Credentials for AWS stuff. | @@ -47,8 +47,9 @@ A Helm chart for gen3 data-portal | global.ddEnabled | bool | `false` | Whether Datadog is enabled. | | global.dev | bool | `true` | Whether the deployment is for development purposes. | | global.dictionaryUrl | string | `"https://s3.amazonaws.com/dictionary-artifacts/datadictionary/develop/schema.json"` | URL of the data dictionary. | -| global.dispatcherJobNum | int | `10` | Number of dispatcher jobs. | +| global.dispatcherJobNum | int | `"10"` | Number of dispatcher jobs. | | global.environment | string | `"default"` | Environment name. This should be the same as vpcname if you're doing an AWS deployment. Currently this is being used to share ALB's if you have multiple namespaces. Might be used other places too. | +| global.frontendRoot | string | `"portal"` | Which app will be served on /. Needs be set to portal for portal, or "gen3ff" for frontendframework. | | global.hostname | string | `"localhost"` | Hostname for the deployment. | | global.kubeBucket | string | `"kube-gen3"` | S3 bucket name for Kubernetes manifest files. | | global.logsBucket | string | `"logs-gen3"` | S3 bucket name for log files. | @@ -56,8 +57,8 @@ A Helm chart for gen3 data-portal | global.netPolicy | bool | `true` | Whether network policies are enabled. | | global.pdb | bool | `false` | If the service will be deployed with a Pod Disruption Budget. Note- you need to have more than 2 replicas for the pdb to be deployed. | | global.portalApp | string | `"gitops"` | Portal application name. | -| global.postgres | map | `{"dbCreate":true,"master":{"host":null,"password":null,"port":"5432","username":"postgres"}}` | Postgres database configuration. | | global.postgres.dbCreate | bool | `true` | Whether the database should be created. | +| global.postgres.externalSecret | string | `""` | Name of external secret. Disabled if empty | | global.postgres.master | map | `{"host":null,"password":null,"port":"5432","username":"postgres"}` | Master credentials to postgres. This is going to be the default postgres server being used for each service, unless each service specifies their own postgres | | global.postgres.master.host | string | `nil` | hostname of postgres server | | global.postgres.master.password | string | `nil` | password for superuser in postgres. This is used to create or restore databases | @@ -66,7 +67,7 @@ A Helm chart for gen3 data-portal | global.publicDataSets | bool | `true` | Whether public datasets are enabled. | | global.revproxyArn | string | `"arn:aws:acm:us-east-1:123456:certificate"` | ARN of the reverse proxy certificate. | | global.tierAccessLevel | string | `"libre"` | Access level for tiers. acceptable values for `tier_access_level` are: `libre`, `regular` and `private`. If omitted, by default common will be treated as `private`. | -| global.tierAccessLimit | int | `1000` | Only relevant if tireAccessLevel is set to "regular". Summary charts below this limit will not appear for aggregated data. | +| global.tierAccessLimit | int | `"1000"` | Only relevant if tireAccessLevel is set to "regular". Summary charts below this limit will not appear for aggregated data. | | image | map | `{"pullPolicy":"IfNotPresent","repository":"quay.io/cdis/data-portal","tag":"master"}` | Docker image information. | | image.pullPolicy | string | `"IfNotPresent"` | Docker pull policy. | | image.repository | string | `"quay.io/cdis/data-portal"` | Docker repository. | @@ -100,5 +101,3 @@ A Helm chart for gen3 data-portal | strategy.rollingUpdate.maxUnavailable | int | `"25%"` | Maximum amount of pods that can be unavailable during the update. | | tolerations | list | `[]` | Tolerations to apply to the pod | ----------------------------------------------- -Autogenerated from chart metadata using [helm-docs v1.11.0](https://github.com/norwoodj/helm-docs/releases/v1.11.0) diff --git a/helm/portal/templates/deployment.yaml b/helm/portal/templates/deployment.yaml index 395fbcf5..9fb7d09f 100644 --- a/helm/portal/templates/deployment.yaml +++ b/helm/portal/templates/deployment.yaml @@ -8,6 +8,9 @@ metadata: {{- include "common.datadogLabels" . | nindent 4 }} {{- end }} spec: + {{- if not .Values.autoscaling.enabled }} + replicas: {{ .Values.replicaCount }} + {{- end }} selector: matchLabels: {{- include "portal.selectorLabels" . | nindent 6 }} @@ -41,7 +44,33 @@ spec: secretName: "portal-sponsor-config" - name: privacy-policy configMap: - name: "privacy-policy" + name: "privacy-policy" + optional: true + {{- if .Values.extraImages }} + - name: extra-images-config + configMap: + name: portal-extra-images + - name: extra-images + emptyDir: {} + initContainers: + - name: init + # image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" + image: "quay.io/prometheus/busybox:latest" + imagePullPolicy: {{ .Values.image.pullPolicy }} + volumeMounts: + - name: extra-images-config + mountPath: /data-portal/custom/config.txt + subPath: config.txt + - name: extra-images + mountPath: /data-portal/custom/images + command: + - sh + - -c + - | + cd /data-portal/custom/images/; + cat /data-portal/custom/config.txt; + xargs -a /data-portal/custom/config.txt -I {} wget {} + {{- end }} containers: - name: portal image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" @@ -56,7 +85,11 @@ spec: # failureThreshold: 30 readinessProbe: httpGet: + {{- if eq "gen3ff" .Values.global.frontendRoot }} + path: /portal + {{- else }} path: / + {{- end }} port: 80 initialDelaySeconds: 30 periodSeconds: 60 @@ -166,11 +199,19 @@ spec: {{- with .Values.dataUploadBucket }} - name: DATA_UPLOAD_BUCKET value: {{ . }} + {{- end }} + {{- if eq "gen3ff" .Values.global.frontendRoot }} + - name: BASENAME + value: /portal {{- end }} # S3 bucket name for data upload, for setting up CSP #GEN3_DATA_UPLOAD_BUCKET|-value: ""-| # - name: BASENAME volumeMounts: + {{- if .Values.extraImages }} + - name: extra-images + mountPath: /data-portal/custom/images + {{- end }} - name: "config-volume" mountPath: "/data-portal/data/config/gitops.json" subPath: "gitops.json" diff --git a/helm/portal/templates/extra-images-conf.yaml b/helm/portal/templates/extra-images-conf.yaml new file mode 100644 index 00000000..a72d703a --- /dev/null +++ b/helm/portal/templates/extra-images-conf.yaml @@ -0,0 +1,11 @@ +{{- with .Values.extraImages }} +apiVersion: v1 +kind: ConfigMap +metadata: + name: portal-extra-images +data: + config.txt: + {{- range . }} + {{ .url }} + {{ end }} + {{- end }} \ No newline at end of file diff --git a/helm/portal/templates/secret.yaml b/helm/portal/templates/secret.yaml index 16a7c037..2a669ee4 100644 --- a/helm/portal/templates/secret.yaml +++ b/helm/portal/templates/secret.yaml @@ -4,10 +4,10 @@ metadata: name: portal-config data: {{- if .Values.gitops.createdby }} - gitops-createdby: | + gitops-createdby.png: | {{- .Values.gitops.createdby | nindent 4 }} {{- else }} - gitops-createdby: | + gitops-createdby.png: | {{- (.Files.Get "defaults/gitops-createdby.png" | b64enc) | nindent 4 }} {{- end }} {{- if .Values.gitops.css }} @@ -19,10 +19,10 @@ data: {{- end }} {{- if .Values.gitops.favicon }} gitops-favicon.ico: | - {{- .Values.gitops.favicon | b64enc | nindent 4 }} + {{- .Values.gitops.favicon | nindent 4 }} {{- else }} gitops-favicon.ico: | - {{- (.Files.Get "defaults/gitops-favicon.ico" ) | nindent 4 }} + {{- (.Files.Get "defaults/gitops-favicon.ico" | b64enc) | nindent 4 }} {{- end }} {{- if .Values.gitops.json }} gitops.json: | diff --git a/helm/portal/values.yaml b/helm/portal/values.yaml index 09105170..7e0c6723 100644 --- a/helm/portal/values.yaml +++ b/helm/portal/values.yaml @@ -1,7 +1,8 @@ # Default values for portal. # This is a YAML-formatted file. # Declare variables to be passed into your templates. -# -- (map) Global configuration options. + +# Global configuration global: # -- (map) AWS configuration aws: @@ -13,10 +14,12 @@ global: awsSecretAccessKey: # -- (bool) Whether the deployment is for development purposes. dev: true - # -- (map) Postgres database configuration. + postgres: # -- (bool) Whether the database should be created. dbCreate: true + # -- (string) Name of external secret. Disabled if empty + externalSecret: "" # -- (map) Master credentials to postgres. This is going to be the default postgres server being used for each service, unless each service specifies their own postgres master: # -- (string) hostname of postgres server @@ -46,17 +49,19 @@ global: # -- (string) Access level for tiers. acceptable values for `tier_access_level` are: `libre`, `regular` and `private`. If omitted, by default common will be treated as `private`. tierAccessLevel: libre # -- (int) Only relevant if tireAccessLevel is set to "regular". Summary charts below this limit will not appear for aggregated data. - tierAccessLimit: 1000 + tierAccessLimit: "1000" # -- (bool) Whether network policies are enabled. netPolicy: true # -- (int) Number of dispatcher jobs. - dispatcherJobNum: 10 + dispatcherJobNum: "10" # -- (bool) Whether Datadog is enabled. ddEnabled: false # -- (bool) If the service will be deployed with a Pod Disruption Budget. Note- you need to have more than 2 replicas for the pdb to be deployed. pdb: false # -- (int) The minimum amount of pods that are available at all times if the PDB is deployed. minAvialable: 1 + # -- (string) Which app will be served on /. Needs be set to portal for portal, or "gen3ff" for frontendframework. + frontendRoot: "portal" # -- (int) Number of replicas for the deployment. replicaCount: 1 @@ -198,6 +203,12 @@ datadogProfilingEnabled: true # -- (int) A value between 0 and 1, that represents the percentage of requests that will be traced. For example, a value of 0.5 means that 50% of requests will be traced. datadogTraceSampleRate: 1 + +# -- (map) Extra images to be mounted in the deployment. +extraImages: + # - url: https://raw.githubusercontent.com/uc-cdis/gen3-helm/master/docs/images/gen3-blue-dark.png + + # -- (map) GitOps configuration for portal gitops: # -- (string) multiline string - gitops.json diff --git a/helm/requestor/Chart.yaml b/helm/requestor/Chart.yaml index 552ae3bc..e0c06a88 100644 --- a/helm/requestor/Chart.yaml +++ b/helm/requestor/Chart.yaml @@ -15,7 +15,7 @@ type: application # This is the chart version. This version number should be incremented each time you make changes # to the chart and its templates, including the app version. # Versions are expected to follow Semantic Versioning (https://semver.org/) -version: 0.1.9 +version: 0.1.11 # This is the version number of the application being deployed. This version number should be # incremented each time you make changes to the application. Versions are not expected to @@ -26,7 +26,7 @@ appVersion: "master" dependencies: - name: common - version: 0.1.8 + version: 0.1.10 repository: file://../common - name: postgresql version: 11.9.13 diff --git a/helm/requestor/README.md b/helm/requestor/README.md index e1a29a8f..2e3cc416 100644 --- a/helm/requestor/README.md +++ b/helm/requestor/README.md @@ -1,6 +1,6 @@ # requestor -![Version: 0.1.9](https://img.shields.io/badge/Version-0.1.9-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: master](https://img.shields.io/badge/AppVersion-master-informational?style=flat-square) +![Version: 0.1.11](https://img.shields.io/badge/Version-0.1.11-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: master](https://img.shields.io/badge/AppVersion-master-informational?style=flat-square) A Helm chart for gen3 Requestor Service @@ -8,7 +8,7 @@ A Helm chart for gen3 Requestor Service | Repository | Name | Version | |------------|------|---------| -| file://../common | common | 0.1.8 | +| file://../common | common | 0.1.10 | | https://charts.bitnami.com/bitnami | postgresql | 11.9.13 | ## Values @@ -36,7 +36,8 @@ A Helm chart for gen3 Requestor Service | datadogLogsInjection | bool | `true` | If enabled, the Datadog Agent will automatically inject Datadog-specific metadata into your application logs. | | datadogProfilingEnabled | bool | `true` | If enabled, the Datadog Agent will collect profiling data for your application using the Continuous Profiler. This data can be used to identify performance bottlenecks and optimize your application. | | datadogTraceSampleRate | int | `1` | A value between 0 and 1, that represents the percentage of requests that will be traced. For example, a value of 0.5 means that 50% of requests will be traced. | -| global | map | `{"addDbgap":false,"aws":{"awsAccessKeyId":null,"awsSecretAccessKey":null,"enabled":false},"ddEnabled":false,"dev":true,"dictionaryUrl":"https://s3.amazonaws.com/dictionary-artifacts/datadictionary/develop/schema.json","dispatcherJobNum":10,"environment":"default","hostname":"localhost","kubeBucket":"kube-gen3","logsBucket":"logs-gen3","minAvialable":1,"netPolicy":true,"onlyDbgap":false,"pdb":false,"portalApp":"gitops","postgres":{"dbCreate":true,"master":{"host":null,"password":null,"port":"5432","username":"postgres"}},"publicDataSets":true,"revproxyArn":"arn:aws:acm:us-east-1:123456:certificate","slack_send_dbgap":false,"slack_webhook":"None","syncFromDbgap":false,"tierAccessLevel":"libre","userYamlS3Path":"s3://cdis-gen3-users/helm-test/user.yaml","usersync":false}` | Global configuration options. | +| externalSecrets | map | `{"dbcreds":null}` | External Secrets settings. | +| externalSecrets.dbcreds | string | `nil` | Will override the name of the aws secrets manager secret. Default is "Values.global.environment-.Chart.Name-creds" | | global.addDbgap | bool | `false` | Force attempting a dbgap sync if "true", falls back on user.yaml | | global.aws | map | `{"awsAccessKeyId":null,"awsSecretAccessKey":null,"enabled":false}` | AWS configuration | | global.aws.awsAccessKeyId | string | `nil` | Credentials for AWS stuff. | @@ -45,8 +46,11 @@ A Helm chart for gen3 Requestor Service | global.ddEnabled | bool | `false` | Whether Datadog is enabled. | | global.dev | bool | `true` | Whether the deployment is for development purposes. | | global.dictionaryUrl | string | `"https://s3.amazonaws.com/dictionary-artifacts/datadictionary/develop/schema.json"` | URL of the data dictionary. | -| global.dispatcherJobNum | int | `10` | Number of dispatcher jobs. | +| global.dispatcherJobNum | int | `"10"` | Number of dispatcher jobs. | | global.environment | string | `"default"` | Environment name. This should be the same as vpcname if you're doing an AWS deployment. Currently this is being used to share ALB's if you have multiple namespaces. Might be used other places too. | +| global.externalSecrets | map | `{"deploy":false,"separateSecretStore":false}` | External Secrets settings. | +| global.externalSecrets.deploy | bool | `false` | Will use ExternalSecret resources to pull secrets from Secrets Manager instead of creating them locally. Be cautious as this will override any requestor secrets you have deployed. | +| global.externalSecrets.separateSecretStore | string | `false` | Will deploy a separate External Secret Store for this service. | | global.hostname | string | `"localhost"` | Hostname for the deployment. | | global.kubeBucket | string | `"kube-gen3"` | S3 bucket name for Kubernetes manifest files. | | global.logsBucket | string | `"logs-gen3"` | S3 bucket name for log files. | @@ -55,8 +59,8 @@ A Helm chart for gen3 Requestor Service | global.onlyDbgap | bool | `false` | Forces ONLY a dbgap sync if "true", IGNORING user.yaml | | global.pdb | bool | `false` | If the service will be deployed with a Pod Disruption Budget. Note- you need to have more than 2 replicas for the pdb to be deployed. | | global.portalApp | string | `"gitops"` | Portal application name. | -| global.postgres | map | `{"dbCreate":true,"master":{"host":null,"password":null,"port":"5432","username":"postgres"}}` | Postgres database configuration. | | global.postgres.dbCreate | bool | `true` | Whether the database should be created. | +| global.postgres.externalSecret | string | `""` | Name of external secret. Disabled if empty | | global.postgres.master | map | `{"host":null,"password":null,"port":"5432","username":"postgres"}` | Master credentials to postgres. This is going to be the default postgres server being used for each service, unless each service specifies their own postgres | | global.postgres.master.host | string | `nil` | hostname of postgres server | | global.postgres.master.password | string | `nil` | password for superuser in postgres. This is used to create or restore databases | @@ -101,6 +105,9 @@ A Helm chart for gen3 Requestor Service | resources.requests.cpu | string | `0.1` | The amount of CPU requested | | resources.requests.memory | string | `"12Mi"` | The amount of memory requested | | revisionHistoryLimit | int | `2` | Number of old revisions to retain | +| secrets | map | `{"awsAccessKeyId":null,"awsSecretAccessKey":null}` | Secret information for External Secrets. | +| secrets.awsAccessKeyId | str | `nil` | AWS access key ID. Overrides global key. | +| secrets.awsSecretAccessKey | str | `nil` | AWS secret access key ID. Overrides global key. | | selectorLabels | map | `nil` | Will completely override the selectorLabels defined in the common chart's _label_setup.tpl | | service | map | `{"port":[{"name":"http","port":80,"protocol":"TCP","targetPort":80}],"type":"ClusterIP"}` | Kubernetes service information. | | service.port | int | `[{"name":"http","port":80,"protocol":"TCP","targetPort":80}]` | The port number that the service exposes. | @@ -114,5 +121,3 @@ A Helm chart for gen3 Requestor Service | strategy.rollingUpdate.maxUnavailable | int | `0` | Maximum amount of pods that can be unavailable during the update. | | volumeMounts | list | `[{"mountPath":"/requestor/deployment/wsgi/gunicorn.conf.py","name":"wsgi-config","subPath":"gunicorn.conf.py"}]` | Volumes to mount to the container. | ----------------------------------------------- -Autogenerated from chart metadata using [helm-docs v1.11.0](https://github.com/norwoodj/helm-docs/releases/v1.11.0) diff --git a/helm/requestor/templates/aws-config.yaml b/helm/requestor/templates/aws-config.yaml new file mode 100644 index 00000000..398770d3 --- /dev/null +++ b/helm/requestor/templates/aws-config.yaml @@ -0,0 +1,3 @@ +{{- if or (.Values.secrets.awsSecretAccessKey) (.Values.global.aws.awsSecretAccessKey ) }} +{{ include "common.awsconfig" . }} +{{- end -}} \ No newline at end of file diff --git a/helm/requestor/templates/db-init.yaml b/helm/requestor/templates/db-init.yaml index abbefb6e..5ef14e87 100644 --- a/helm/requestor/templates/db-init.yaml +++ b/helm/requestor/templates/db-init.yaml @@ -1,6 +1,6 @@ -{{ include "common.db_setup_job" . }} ---- {{ include "common.db-secret" . }} --- -{{ include "common.db_setup_sa" . }} +{{ include "common.db_setup_job" . }} --- +{{ include "common.db_setup_sa" . }} +--- \ No newline at end of file diff --git a/helm/requestor/templates/external-secret.yaml b/helm/requestor/templates/external-secret.yaml new file mode 100644 index 00000000..70c278fe --- /dev/null +++ b/helm/requestor/templates/external-secret.yaml @@ -0,0 +1 @@ +{{ include "common.externalSecret.db" . }} \ No newline at end of file diff --git a/helm/requestor/templates/secret-store.yaml b/helm/requestor/templates/secret-store.yaml new file mode 100644 index 00000000..771c7760 --- /dev/null +++ b/helm/requestor/templates/secret-store.yaml @@ -0,0 +1,3 @@ +{{ if .Values.global.externalSecrets.separateSecretStore }} +{{ include "common.secretstore" . }} +{{- end }} \ No newline at end of file diff --git a/helm/requestor/values.yaml b/helm/requestor/values.yaml index 88063add..f233cb84 100644 --- a/helm/requestor/values.yaml +++ b/helm/requestor/values.yaml @@ -2,7 +2,8 @@ # This is a YAML-formatted file. # Declare variables to be passed into your templates. -# -- (map) Global configuration options. + +# Global configuration global: # -- (map) AWS configuration aws: @@ -14,10 +15,12 @@ global: awsSecretAccessKey: # -- (bool) Whether the deployment is for development purposes. dev: true - # -- (map) Postgres database configuration. + postgres: # -- (bool) Whether the database should be created. dbCreate: true + # -- (string) Name of external secret. Disabled if empty + externalSecret: "" # -- (map) Master credentials to postgres. This is going to be the default postgres server being used for each service, unless each service specifies their own postgres master: # -- (string) hostname of postgres server @@ -63,13 +66,30 @@ global: # -- (bool) Whether network policies are enabled. netPolicy: true # -- (int) Number of dispatcher jobs. - dispatcherJobNum: 10 + dispatcherJobNum: "10" # -- (bool) Whether Datadog is enabled. ddEnabled: false # -- (bool) If the service will be deployed with a Pod Disruption Budget. Note- you need to have more than 2 replicas for the pdb to be deployed. pdb: false # -- (int) The minimum amount of pods that are available at all times if the PDB is deployed. minAvialable: 1 + # -- (map) External Secrets settings. + externalSecrets: + # -- (bool) Will use ExternalSecret resources to pull secrets from Secrets Manager instead of creating them locally. Be cautious as this will override any requestor secrets you have deployed. + deploy: false + # -- (string) Will deploy a separate External Secret Store for this service. + separateSecretStore: false + +# -- (map) External Secrets settings. +externalSecrets: + # -- (string) Will override the name of the aws secrets manager secret. Default is "Values.global.environment-.Chart.Name-creds" + dbcreds: +# -- (map) Secret information for External Secrets. +secrets: + # -- (str) AWS access key ID. Overrides global key. + awsAccessKeyId: + # -- (str) AWS secret access key ID. Overrides global key. + awsSecretAccessKey: # -- (map) Postgres database configuration. If db does not exist in postgres cluster and dbCreate is set ot true then these databases will be created for you postgres: diff --git a/helm/revproxy/Chart.yaml b/helm/revproxy/Chart.yaml index 09320900..49401320 100644 --- a/helm/revproxy/Chart.yaml +++ b/helm/revproxy/Chart.yaml @@ -15,7 +15,7 @@ type: application # This is the chart version. This version number should be incremented each time you make changes # to the chart and its templates, including the app version. # Versions are expected to follow Semantic Versioning (https://semver.org/) -version: 0.1.12 +version: 0.1.16 # This is the version number of the application being deployed. This version number should be # incremented each time you make changes to the application. Versions are not expected to @@ -25,5 +25,5 @@ appVersion: "master" dependencies: - name: common - version: 0.1.8 + version: 0.1.11 repository: file://../common diff --git a/helm/revproxy/README.md b/helm/revproxy/README.md index ff1b01e7..53a75103 100644 --- a/helm/revproxy/README.md +++ b/helm/revproxy/README.md @@ -1,6 +1,6 @@ # revproxy -![Version: 0.1.12](https://img.shields.io/badge/Version-0.1.12-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: master](https://img.shields.io/badge/AppVersion-master-informational?style=flat-square) +![Version: 0.1.16](https://img.shields.io/badge/Version-0.1.16-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: master](https://img.shields.io/badge/AppVersion-master-informational?style=flat-square) A Helm chart for gen3 revproxy @@ -8,7 +8,7 @@ A Helm chart for gen3 revproxy | Repository | Name | Version | |------------|------|---------| -| file://../common | common | 0.1.8 | +| file://../common | common | 0.1.11 | ## Values @@ -26,15 +26,17 @@ A Helm chart for gen3 revproxy | datadogProfilingEnabled | bool | `true` | If enabled, the Datadog Agent will collect profiling data for your application using the Continuous Profiler. This data can be used to identify performance bottlenecks and optimize your application. | | datadogTraceSampleRate | int | `1` | A value between 0 and 1, that represents the percentage of requests that will be traced. For example, a value of 0.5 means that 50% of requests will be traced. | | fullnameOverride | string | `""` | Override the full name of the deployment. | -| global | map | `{"aws":{"awsAccessKeyId":null,"awsSecretAccessKey":null,"enabled":false},"ddEnabled":false,"dev":true,"dictionaryUrl":"https://s3.amazonaws.com/dictionary-artifacts/datadictionary/develop/schema.json","dispatcherJobNum":10,"environment":"default","hostname":"localhost","kubeBucket":"kube-gen3","logsBucket":"logs-gen3","minAvialable":1,"netPolicy":true,"pdb":false,"portalApp":"gitops","postgres":{"dbCreate":true,"master":{"host":null,"password":null,"port":"5432","username":"postgres"}},"publicDataSets":true,"revproxyArn":"arn:aws:acm:us-east-1:123456:certificate","tierAccessLevel":"libre","tierAccessLimit":1000,"tls":{"cert":null,"key":null}}` | Global configuration options. | -| global.aws | map | `{"awsAccessKeyId":null,"awsSecretAccessKey":null,"enabled":false}` | AWS configuration | +| global.aws | map | `{"awsAccessKeyId":null,"awsSecretAccessKey":null,"enabled":false,"wafv2":{"enabled":false,"wafAclArn":null}}` | AWS configuration | | global.aws.awsAccessKeyId | string | `nil` | Credentials for AWS stuff. | | global.aws.awsSecretAccessKey | string | `nil` | Credentials for AWS stuff. | | global.aws.enabled | bool | `false` | Set to true if deploying to AWS. Controls ingress annotations. | +| global.aws.wafv2 | map | `{"enabled":false,"wafAclArn":null}` | WAF configuration | +| global.aws.wafv2.enabled | bool | `false` | Set to true if using AWS WAFv2 | +| global.aws.wafv2.wafAclArn | string | `nil` | ARN for the WAFv2 ACL. | | global.ddEnabled | bool | `false` | Whether Datadog is enabled. | | global.dev | bool | `true` | Whether the deployment is for development purposes. | | global.dictionaryUrl | string | `"https://s3.amazonaws.com/dictionary-artifacts/datadictionary/develop/schema.json"` | URL of the data dictionary. | -| global.dispatcherJobNum | int | `10` | Number of dispatcher jobs. | +| global.dispatcherJobNum | int | `"10"` | Number of dispatcher jobs. | | global.environment | string | `"default"` | Environment name. This should be the same as vpcname if you're doing an AWS deployment. Currently this is being used to share ALB's if you have multiple namespaces. Might be used other places too. | | global.hostname | string | `"localhost"` | Hostname for the deployment. | | global.kubeBucket | string | `"kube-gen3"` | S3 bucket name for Kubernetes manifest files. | @@ -43,8 +45,8 @@ A Helm chart for gen3 revproxy | global.netPolicy | bool | `true` | Whether network policies are enabled. | | global.pdb | bool | `false` | If the service will be deployed with a Pod Disruption Budget. Note- you need to have more than 2 replicas for the pdb to be deployed. | | global.portalApp | string | `"gitops"` | Portal application name. | -| global.postgres | map | `{"dbCreate":true,"master":{"host":null,"password":null,"port":"5432","username":"postgres"}}` | Postgres database configuration. | | global.postgres.dbCreate | bool | `true` | Whether the database should be created. | +| global.postgres.externalSecret | string | `""` | Name of external secret. Disabled if empty | | global.postgres.master | map | `{"host":null,"password":null,"port":"5432","username":"postgres"}` | Master credentials to postgres. This is going to be the default postgres server being used for each service, unless each service specifies their own postgres | | global.postgres.master.host | string | `nil` | hostname of postgres server | | global.postgres.master.password | string | `nil` | password for superuser in postgres. This is used to create or restore databases | @@ -53,7 +55,9 @@ A Helm chart for gen3 revproxy | global.publicDataSets | bool | `true` | Whether public datasets are enabled. | | global.revproxyArn | string | `"arn:aws:acm:us-east-1:123456:certificate"` | ARN of the reverse proxy certificate. | | global.tierAccessLevel | string | `"libre"` | Access level for tiers. acceptable values for `tier_access_level` are: `libre`, `regular` and `private`. If omitted, by default common will be treated as `private` | -| global.tierAccessLimit | int | `1000` | Only relevant if tireAccessLevel is set to "regular". Summary charts below this limit will not appear for aggregated data. | +| global.tierAccessLimit | int | `"1000"` | Only relevant if tireAccessLevel is set to "regular". Summary charts below this limit will not appear for aggregated data. | +| global.tls.cert | string | `nil` | | +| global.tls.key | string | `nil` | | | image | map | `{"pullPolicy":"Always","repository":"nginx","tag":"stable-perl"}` | Docker image information. | | image.pullPolicy | string | `"Always"` | Docker pull policy. | | image.repository | string | `"nginx"` | Docker repository. | @@ -103,5 +107,3 @@ A Helm chart for gen3 revproxy | tolerations | list | `[]` | Tolerations to use for the deployment. | | userhelperEnabled | bool | `false` | | ----------------------------------------------- -Autogenerated from chart metadata using [helm-docs v1.11.0](https://github.com/norwoodj/helm-docs/releases/v1.11.0) diff --git a/helm/revproxy/gen3.nginx.conf/gen3ff-as-root/frontend-framework-service.conf b/helm/revproxy/gen3.nginx.conf/gen3ff-as-root/frontend-framework-service.conf index ac2cb75f..1e2259b9 100644 --- a/helm/revproxy/gen3.nginx.conf/gen3ff-as-root/frontend-framework-service.conf +++ b/helm/revproxy/gen3.nginx.conf/gen3ff-as-root/frontend-framework-service.conf @@ -6,3 +6,9 @@ set $upstream http://frontend-framework-service.$namespace.svc.cluster.local; proxy_pass $upstream; } + + location /api/auth/ { + set $proxy_service "frontend-framework"; + set $upstream http://frontend-framework-service.$namespace.svc.cluster.local; + proxy_pass $upstream; + } diff --git a/helm/revproxy/gen3.nginx.conf/portal-as-root/frontend-framework-service.conf b/helm/revproxy/gen3.nginx.conf/portal-as-root/frontend-framework-service.conf index dbb24e4b..d3e13507 100644 --- a/helm/revproxy/gen3.nginx.conf/portal-as-root/frontend-framework-service.conf +++ b/helm/revproxy/gen3.nginx.conf/portal-as-root/frontend-framework-service.conf @@ -11,3 +11,9 @@ set $upstream http://frontend-framework-service.$namespace.svc.cluster.local; proxy_pass $upstream; } + + location /ff/api/auth/ { + set $proxy_service "frontend-framework"; + set $upstream http://frontend-framework-service.$namespace.svc.cluster.local; + proxy_pass $upstream; + } diff --git a/helm/revproxy/gen3.nginx.conf/portal-service.conf b/helm/revproxy/gen3.nginx.conf/portal-service.conf deleted file mode 100644 index 35d64cca..00000000 --- a/helm/revproxy/gen3.nginx.conf/portal-service.conf +++ /dev/null @@ -1,12 +0,0 @@ - location / { - if ($csrf_check !~ ^ok-\S.+$) { - return 403 "failed csrf check"; - } - - - set $proxy_service "portal"; - # $upstream is written to the logs - set $upstream http://portal-service.$namespace.svc.cluster.local; - - proxy_pass $upstream; - } diff --git a/helm/revproxy/nginx/nginx.conf b/helm/revproxy/nginx/nginx.conf index d2be4bd3..0d352578 100644 --- a/helm/revproxy/nginx/nginx.conf +++ b/helm/revproxy/nginx/nginx.conf @@ -320,12 +320,6 @@ http { if ($document_url_env != "") { include /etc/nginx/gen3.conf/documentation-site/*.conf; } - if ($frontend_root_service = "portal") { - include /etc/nginx/gen3.conf/portal-as-root/*.conf; - } - if ($frontend_root_service = "gen3ff") { - include /etc/nginx/gen3.conf/gen3ff-as-root/*.conf; - } location @errorworkspace { # if ($frontend_root_service = "gen3ff") { diff --git a/helm/revproxy/templates/configMaps.yaml b/helm/revproxy/templates/configMaps.yaml index ad7441f9..306617cc 100644 --- a/helm/revproxy/templates/configMaps.yaml +++ b/helm/revproxy/templates/configMaps.yaml @@ -1,19 +1,30 @@ apiVersion: v1 kind: ConfigMap -metadata: +metadata: name: revproxy-nginx-subconf data: {{- range $path, $bytes := .Files.Glob "gen3.nginx.conf/*.conf" }} {{ ($a := split "/" $path)._1 }}: | - {{- $bytes | toString | nindent 4 }} + {{- $bytes | toString | nindent 4 }} {{- end}} +{{- if eq "gen3ff" .Values.global.frontendRoot }} + {{ "frontend-framework-service.conf" }}: | + {{- .Files.Get "gen3.nginx.conf/gen3ff-as-root/frontend-framework-service.conf" | nindent 4}} + {{ "portal-service.conf" }}: | + {{- .Files.Get "gen3.nginx.conf/gen3ff-as-root/portal-service.conf" | nindent 4}} +{{- else }} + {{ "frontend-framework-service.conf" }}: | + {{- .Files.Get "gen3.nginx.conf/portal-as-root/frontend-framework-service.conf"| nindent 4}} + {{ "portal-service.conf" }}: | + {{- .Files.Get "gen3.nginx.conf/portal-as-root/portal-service.conf" | nindent 4}} +{{- end }} --- apiVersion: v1 kind: ConfigMap -metadata: +metadata: name: revproxy-nginx-conf data: {{- range $path, $bytes := .Files.Glob "nginx/*" }} {{ ($a := split "/" $path)._1 }}: | - {{- $bytes | toString | nindent 4 }} + {{- $bytes | toString | nindent 4 }} {{- end}} \ No newline at end of file diff --git a/helm/revproxy/templates/deployment.yaml b/helm/revproxy/templates/deployment.yaml index 043b4e7a..7be59ba4 100644 --- a/helm/revproxy/templates/deployment.yaml +++ b/helm/revproxy/templates/deployment.yaml @@ -75,7 +75,7 @@ spec: path: /_status port: 80 initialDelaySeconds: 5 - periodSeconds: 30 + periodSeconds: 3000 readinessProbe: httpGet: path: /_status @@ -125,7 +125,7 @@ spec: secretKeyRef: name: gateway-g3auto key: base64Authz.txt - optional: true + optional: true - name: MDS_AUTHZ valueFrom: secretKeyRef: @@ -192,7 +192,7 @@ spec: echo "modsecurity on;" >> /etc/nginx/gen3_server_modsec.conf echo "modsecurity_rules_file /etc/nginx/modsec/main.conf;" >> /etc/nginx/gen3_server_modsec.conf fi - + exec nginx -g 'daemon off;' {{- with .Values.nodeSelector }} nodeSelector: diff --git a/helm/revproxy/templates/ingress_aws.yaml b/helm/revproxy/templates/ingress_aws.yaml index 7b0760c3..612dad43 100644 --- a/helm/revproxy/templates/ingress_aws.yaml +++ b/helm/revproxy/templates/ingress_aws.yaml @@ -10,6 +10,10 @@ metadata: alb.ingress.kubernetes.io/group.name: {{ .Values.global.environment }} alb.ingress.kubernetes.io/listen-ports: '[{"HTTP": 80}, {"HTTPS":443}]' alb.ingress.kubernetes.io/actions.ssl-redirect: '{"Type": "redirect", "RedirectConfig": { "Protocol": "HTTPS", "Port": "443", "StatusCode": "HTTP_301"}}' + alb.ingress.kubernetes.io/ssl-policy: ELBSecurityPolicy-TLS13-1-2-Res-FIPS-2023-04 + {{- if .Values.global.aws.wafv2.enabled }} + alb.ingress.kubernetes.io/wafv2-acl-arn: {{ .Values.global.aws.wafv2.wafAclArn }} + {{- end }} spec: ingressClassName: alb rules: diff --git a/helm/revproxy/values.yaml b/helm/revproxy/values.yaml index 9c1c9b02..44d0f3ed 100644 --- a/helm/revproxy/values.yaml +++ b/helm/revproxy/values.yaml @@ -2,7 +2,8 @@ # This is a YAML-formatted file. # Declare variables to be passed into your templates. -# -- (map) Global configuration options. + +# Global configuration global: tls: cert: @@ -15,12 +16,20 @@ global: awsAccessKeyId: # -- (string) Credentials for AWS stuff. awsSecretAccessKey: + # -- (map) WAF configuration + wafv2: + # -- (bool) Set to true if using AWS WAFv2 + enabled: false + # -- (string) ARN for the WAFv2 ACL. + wafAclArn: # -- (bool) Whether the deployment is for development purposes. dev: true - # -- (map) Postgres database configuration. + postgres: # -- (bool) Whether the database should be created. dbCreate: true + # -- (string) Name of external secret. Disabled if empty + externalSecret: "" # -- (map) Master credentials to postgres. This is going to be the default postgres server being used for each service, unless each service specifies their own postgres master: # -- (string) hostname of postgres server @@ -50,11 +59,11 @@ global: # -- (string) Access level for tiers. acceptable values for `tier_access_level` are: `libre`, `regular` and `private`. If omitted, by default common will be treated as `private` tierAccessLevel: libre # -- (int) Only relevant if tireAccessLevel is set to "regular". Summary charts below this limit will not appear for aggregated data. - tierAccessLimit: 1000 + tierAccessLimit: "1000" # -- (bool) Whether network policies are enabled. netPolicy: true # -- (int) Number of dispatcher jobs. - dispatcherJobNum: 10 + dispatcherJobNum: "10" # -- (bool) Whether Datadog is enabled. ddEnabled: false # -- (bool) If the service will be deployed with a Pod Disruption Budget. Note- you need to have more than 2 replicas for the pdb to be deployed. diff --git a/helm/sheepdog/Chart.yaml b/helm/sheepdog/Chart.yaml index 5156d475..ea4bcc32 100644 --- a/helm/sheepdog/Chart.yaml +++ b/helm/sheepdog/Chart.yaml @@ -15,7 +15,7 @@ type: application # This is the chart version. This version number should be incremented each time you make changes # to the chart and its templates, including the app version. # Versions are expected to follow Semantic Versioning (https://semver.org/) -version: 0.1.11 +version: 0.1.14 # This is the version number of the application being deployed. This version number should be # incremented each time you make changes to the application. Versions are not expected to @@ -25,7 +25,7 @@ appVersion: "master" dependencies: - name: common - version: 0.1.8 + version: 0.1.10 repository: file://../common - name: postgresql version: 11.9.13 diff --git a/helm/sheepdog/README.md b/helm/sheepdog/README.md index 59019ee5..10e73e44 100644 --- a/helm/sheepdog/README.md +++ b/helm/sheepdog/README.md @@ -1,6 +1,6 @@ # sheepdog -![Version: 0.1.11](https://img.shields.io/badge/Version-0.1.11-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: master](https://img.shields.io/badge/AppVersion-master-informational?style=flat-square) +![Version: 0.1.14](https://img.shields.io/badge/Version-0.1.14-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: master](https://img.shields.io/badge/AppVersion-master-informational?style=flat-square) A Helm chart for gen3 Sheepdog Service @@ -8,7 +8,7 @@ A Helm chart for gen3 Sheepdog Service | Repository | Name | Version | |------------|------|---------| -| file://../common | common | 0.1.8 | +| file://../common | common | 0.1.10 | | https://charts.bitnami.com/bitnami | postgresql | 11.9.13 | ## Values @@ -37,8 +37,9 @@ A Helm chart for gen3 Sheepdog Service | datadogProfilingEnabled | bool | `true` | If enabled, the Datadog Agent will collect profiling data for your application using the Continuous Profiler. This data can be used to identify performance bottlenecks and optimize your application. | | datadogTraceSampleRate | int | `1` | A value between 0 and 1, that represents the percentage of requests that will be traced. For example, a value of 0.5 means that 50% of requests will be traced. | | dictionaryUrl | string | `"https://s3.amazonaws.com/dictionary-artifacts/datadictionary/develop/schema.json"` | URL of the data dictionary. | +| externalSecrets | map | `{"dbcreds":null}` | External Secrets settings. | +| externalSecrets.dbcreds | string | `nil` | Will override the name of the aws secrets manager secret. Default is "Values.global.environment-.Chart.Name-creds" | | fenceUrl | string | `"http://fence-service"` | URL for the fence service | -| global | map | `{"aws":{"awsAccessKeyId":null,"awsSecretAccessKey":null,"enabled":false},"ddEnabled":false,"dev":true,"dictionaryUrl":"https://s3.amazonaws.com/dictionary-artifacts/datadictionary/develop/schema.json","dispatcherJobNum":10,"environment":"default","hostname":"localhost","kubeBucket":"kube-gen3","logsBucket":"logs-gen3","minAvialable":1,"netPolicy":true,"pdb":false,"portalApp":"gitops","postgres":{"dbCreate":true,"master":{"host":null,"password":null,"port":"5432","username":"postgres"}},"publicDataSets":true,"revproxyArn":"arn:aws:acm:us-east-1:123456:certificate","tierAccessLevel":"libre"}` | Global configuration options. | | global.aws | map | `{"awsAccessKeyId":null,"awsSecretAccessKey":null,"enabled":false}` | AWS configuration | | global.aws.awsAccessKeyId | string | `nil` | Credentials for AWS stuff. | | global.aws.awsSecretAccessKey | string | `nil` | Credentials for AWS stuff. | @@ -46,8 +47,11 @@ A Helm chart for gen3 Sheepdog Service | global.ddEnabled | bool | `false` | Whether Datadog is enabled. | | global.dev | bool | `true` | Whether the deployment is for development purposes. | | global.dictionaryUrl | string | `"https://s3.amazonaws.com/dictionary-artifacts/datadictionary/develop/schema.json"` | URL of the data dictionary. | -| global.dispatcherJobNum | int | `10` | Number of dispatcher jobs. | +| global.dispatcherJobNum | int | `"10"` | Number of dispatcher jobs. | | global.environment | string | `"default"` | Environment name. This should be the same as vpcname if you're doing an AWS deployment. Currently this is being used to share ALB's if you have multiple namespaces. Might be used other places too. | +| global.externalSecrets | map | `{"deploy":false,"separateSecretStore":false}` | External Secrets settings. | +| global.externalSecrets.deploy | bool | `false` | Will use ExternalSecret resources to pull secrets from Secrets Manager instead of creating them locally. Be cautious as this will override any sheepdog secrets you have deployed. | +| global.externalSecrets.separateSecretStore | string | `false` | Will deploy a separate External Secret Store for this service. | | global.hostname | string | `"localhost"` | Hostname for the deployment. | | global.kubeBucket | string | `"kube-gen3"` | S3 bucket name for Kubernetes manifest files. | | global.logsBucket | string | `"logs-gen3"` | S3 bucket name for log files. | @@ -55,8 +59,8 @@ A Helm chart for gen3 Sheepdog Service | global.netPolicy | bool | `true` | Whether network policies are enabled. | | global.pdb | bool | `false` | If the service will be deployed with a Pod Disruption Budget. Note- you need to have more than 2 replicas for the pdb to be deployed. | | global.portalApp | string | `"gitops"` | Portal application name. | -| global.postgres | map | `{"dbCreate":true,"master":{"host":null,"password":null,"port":"5432","username":"postgres"}}` | Postgres database configuration. | | global.postgres.dbCreate | bool | `true` | Whether the database should be created. | +| global.postgres.externalSecret | string | `""` | Name of external secret. Disabled if empty | | global.postgres.master | map | `{"host":null,"password":null,"port":"5432","username":"postgres"}` | Master credentials to postgres. This is going to be the default postgres server being used for each service, unless each service specifies their own postgres | | global.postgres.master.host | string | `nil` | hostname of postgres server | | global.postgres.master.password | string | `nil` | password for superuser in postgres. This is used to create or restore databases | @@ -65,10 +69,10 @@ A Helm chart for gen3 Sheepdog Service | global.publicDataSets | bool | `true` | Whether public datasets are enabled. | | global.revproxyArn | string | `"arn:aws:acm:us-east-1:123456:certificate"` | ARN of the reverse proxy certificate. | | global.tierAccessLevel | string | `"libre"` | Access level for tiers. acceptable values for `tier_access_level` are: `libre`, `regular` and `private`. If omitted, by default common will be treated as `private` | -| image | map | `{"pullPolicy":"Always","repository":"quay.io/cdis/sheepdog","tag":"helm-test"}` | Docker image information. | +| image | map | `{"pullPolicy":"Always","repository":"quay.io/cdis/sheepdog","tag":"bug_auth-audience"}` | Docker image information. | | image.pullPolicy | string | `"Always"` | Docker pull policy. | | image.repository | string | `"quay.io/cdis/sheepdog"` | Docker repository. | -| image.tag | string | `"helm-test"` | Overrides the image tag whose default is the chart appVersion. | +| image.tag | string | `"bug_auth-audience"` | Overrides the image tag whose default is the chart appVersion. | | indexdUrl | string | `"http://indexd-service"` | URL for the indexd service | | partOf | string | `"Core-Service"` | Label to help organize pods and their use. Any value is valid, but use "_" or "-" to divide words. | | podAnnotations | map | `{"gen3.io/network-ingress":"sheepdog"}` | Annotations to add to the pod | @@ -93,20 +97,9 @@ A Helm chart for gen3 Sheepdog Service | resources.requests.cpu | string | `0.3` | The amount of CPU requested | | resources.requests.memory | string | `"12Mi"` | The amount of memory requested | | revisionHistoryLimit | int | `2` | Number of old revisions to retain | -| secrets | map | `{"fence":{"database":"fence","host":"postgres-postgresql.postgres.svc.cluster.local","password":"postgres","user":"postgres"},"gdcapi":{"secretKey":null},"indexd":{"password":"postgres"},"sheepdog":{"database":"sheepdog","host":"postgres-postgresql.postgres.svc.cluster.local","password":"postgres","user":"postgres"}}` | Values for sheepdog secret. | -| secrets.fence | map | `{"database":"fence","host":"postgres-postgresql.postgres.svc.cluster.local","password":"postgres","user":"postgres"}` | Values for sheepdog's access to the fence database. | -| secrets.fence.database | string | `"fence"` | Database name for fence's db. | -| secrets.fence.host | string | `"postgres-postgresql.postgres.svc.cluster.local"` | Host for fence's db. | -| secrets.fence.password | string | `"postgres"` | Password to fence's db. | -| secrets.fence.user | string | `"postgres"` | User for fence's db. | -| secrets.gdcapi.secretKey | string | `nil` | GDCAPI token. | -| secrets.indexd | map | `{"password":"postgres"}` | Values for sheepdog's access to indexd database. | -| secrets.indexd.password | string | `"postgres"` | Password to indexd's db. | -| secrets.sheepdog | map | `{"database":"sheepdog","host":"postgres-postgresql.postgres.svc.cluster.local","password":"postgres","user":"postgres"}` | Values for sheepdog's database. | -| secrets.sheepdog.database | string | `"sheepdog"` | Database name for sheepdog's db. | -| secrets.sheepdog.host | string | `"postgres-postgresql.postgres.svc.cluster.local"` | Host for sheepdog's db. | -| secrets.sheepdog.password | string | `"postgres"` | Password to sheepdog's db. | -| secrets.sheepdog.user | string | `"postgres"` | User for sheepdog's db. | +| secrets | map | `{"awsAccessKeyId":null,"awsSecretAccessKey":null}` | Values for sheepdog secret. | +| secrets.awsAccessKeyId | str | `nil` | AWS access key ID to access the db restore job S3 bucket. Overrides global key. | +| secrets.awsSecretAccessKey | str | `nil` | AWS secret access key ID to access the db restore job S3 bucket. Overrides global key. | | selectorLabels | map | `nil` | Will completely override the selectorLabels defined in the common chart's _label_setup.tpl | | service | map | `{"port":80,"type":"ClusterIP"}` | Kubernetes service information. | | service.port | int | `80` | The port number that the service exposes. | @@ -121,5 +114,3 @@ A Helm chart for gen3 Sheepdog Service | terminationGracePeriodSeconds | int | `50` | sheepdog transactions take forever - try to let the complete before termination | | volumeMounts | list | `[{"mountPath":"/sheepdog/deployment/wsgi/wsgi.py","name":"config-volume","readOnly":true,"subPath":"wsgi.py"},{"mountPath":"/sheepdog/deployment/wsgi/gunicorn.conf.py","name":"wsgi-config","subPath":"gunicorn.conf.py"}]` | Volumes to mount to the container. | ----------------------------------------------- -Autogenerated from chart metadata using [helm-docs v1.11.0](https://github.com/norwoodj/helm-docs/releases/v1.11.0) diff --git a/helm/sheepdog/sheepdog-secret/wsgi.py b/helm/sheepdog/sheepdog-secret/settings.py similarity index 100% rename from helm/sheepdog/sheepdog-secret/wsgi.py rename to helm/sheepdog/sheepdog-secret/settings.py diff --git a/helm/sheepdog/templates/aws-config.yaml b/helm/sheepdog/templates/aws-config.yaml new file mode 100644 index 00000000..398770d3 --- /dev/null +++ b/helm/sheepdog/templates/aws-config.yaml @@ -0,0 +1,3 @@ +{{- if or (.Values.secrets.awsSecretAccessKey) (.Values.global.aws.awsSecretAccessKey ) }} +{{ include "common.awsconfig" . }} +{{- end -}} \ No newline at end of file diff --git a/helm/sheepdog/templates/external-secrets.yaml b/helm/sheepdog/templates/external-secrets.yaml new file mode 100644 index 00000000..70c278fe --- /dev/null +++ b/helm/sheepdog/templates/external-secrets.yaml @@ -0,0 +1 @@ +{{ include "common.externalSecret.db" . }} \ No newline at end of file diff --git a/helm/sheepdog/templates/secret-store.yaml b/helm/sheepdog/templates/secret-store.yaml new file mode 100644 index 00000000..771c7760 --- /dev/null +++ b/helm/sheepdog/templates/secret-store.yaml @@ -0,0 +1,3 @@ +{{ if .Values.global.externalSecrets.separateSecretStore }} +{{ include "common.secretstore" . }} +{{- end }} \ No newline at end of file diff --git a/helm/sheepdog/values.yaml b/helm/sheepdog/values.yaml index f01598d3..65be97a0 100644 --- a/helm/sheepdog/values.yaml +++ b/helm/sheepdog/values.yaml @@ -2,7 +2,8 @@ # This is a YAML-formatted file. # Declare variables to be passed into your templates. -# -- (map) Global configuration options. + +# Global configuration global: # -- (map) AWS configuration aws: @@ -14,10 +15,12 @@ global: awsSecretAccessKey: # -- (bool) Whether the deployment is for development purposes. dev: true - # -- (map) Postgres database configuration. + postgres: # -- (bool) Whether the database should be created. dbCreate: true + # -- (string) Name of external secret. Disabled if empty + externalSecret: "" # -- (map) Master credentials to postgres. This is going to be the default postgres server being used for each service, unless each service specifies their own postgres master: # -- (string) hostname of postgres server @@ -49,13 +52,24 @@ global: # -- (bool) Whether network policies are enabled. netPolicy: true # -- (int) Number of dispatcher jobs. - dispatcherJobNum: 10 + dispatcherJobNum: "10" # -- (bool) Whether Datadog is enabled. ddEnabled: false # -- (bool) If the service will be deployed with a Pod Disruption Budget. Note- you need to have more than 2 replicas for the pdb to be deployed. pdb: false # -- (int) The minimum amount of pods that are available at all times if the PDB is deployed. minAvialable: 1 + # -- (map) External Secrets settings. + externalSecrets: + # -- (bool) Will use ExternalSecret resources to pull secrets from Secrets Manager instead of creating them locally. Be cautious as this will override any sheepdog secrets you have deployed. + deploy: false + # -- (string) Will deploy a separate External Secret Store for this service. + separateSecretStore: false + +# -- (map) External Secrets settings. +externalSecrets: + # -- (string) Will override the name of the aws secrets manager secret. Default is "Values.global.environment-.Chart.Name-creds" + dbcreds: # -- (map) Postgres database configuration. If db does not exist in postgres cluster and dbCreate is set ot true then these databases will be created for you postgres: @@ -154,7 +168,7 @@ image: # -- (string) Docker pull policy. pullPolicy: Always # -- (string) Overrides the image tag whose default is the chart appVersion. - tag: "helm-test" + tag: "bug_auth-audience" # -- (map) Configuration for Nginx sidecar container to be deployed with gunicorn. sidecar: @@ -213,33 +227,10 @@ service: # Secrets # -- (map) Values for sheepdog secret. secrets: - # -- (map) Values for sheepdog's access to the fence database. - fence: - # -- (string) Host for fence's db. - host: postgres-postgresql.postgres.svc.cluster.local - # -- (string) User for fence's db. - user: postgres - # -- (string) Password to fence's db. - password: postgres - # -- (string) Database name for fence's db. - database: fence - # -- (map) Values for sheepdog's database. - sheepdog: - # -- (string) Host for sheepdog's db. - host: postgres-postgresql.postgres.svc.cluster.local - # -- (string) Password to sheepdog's db. - password: postgres - # -- (string) User for sheepdog's db. - user: postgres - # -- (string) Database name for sheepdog's db. - database: sheepdog - gdcapi: - # -- (string) GDCAPI token. - secretKey: - # -- (map) Values for sheepdog's access to indexd database. - indexd: - # -- (string) Password to indexd's db. - password: postgres + # -- (str) AWS access key ID to access the db restore job S3 bucket. Overrides global key. + awsAccessKeyId: + # -- (str) AWS secret access key ID to access the db restore job S3 bucket. Overrides global key. + awsSecretAccessKey: # Values to determine the labels that are used for the deployment, pod, etc. # -- (string) Valid options are "production" or "dev". If invalid option is set- the value will default to "dev". diff --git a/helm/sower/Chart.yaml b/helm/sower/Chart.yaml index 95b847ab..a48e3910 100644 --- a/helm/sower/Chart.yaml +++ b/helm/sower/Chart.yaml @@ -15,7 +15,7 @@ type: application # This is the chart version. This version number should be incremented each time you make changes # to the chart and its templates, including the app version. # Versions are expected to follow Semantic Versioning (https://semver.org/) -version: 0.1.7 +version: 0.1.11 # This is the version number of the application being deployed. This version number should be # incremented each time you make changes to the application. Versions are not expected to @@ -25,5 +25,5 @@ appVersion: "master" dependencies: - name: common - version: 0.1.8 + version: 0.1.10 repository: file://../common diff --git a/helm/sower/README.md b/helm/sower/README.md index 8ccb3ee7..9644ad2e 100644 --- a/helm/sower/README.md +++ b/helm/sower/README.md @@ -1,6 +1,6 @@ # sower -![Version: 0.1.7](https://img.shields.io/badge/Version-0.1.7-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: master](https://img.shields.io/badge/AppVersion-master-informational?style=flat-square) +![Version: 0.1.11](https://img.shields.io/badge/Version-0.1.11-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: master](https://img.shields.io/badge/AppVersion-master-informational?style=flat-square) A Helm chart for gen3 sower @@ -8,7 +8,7 @@ A Helm chart for gen3 sower | Repository | Name | Version | |------------|------|---------| -| file://../common | common | 0.1.8 | +| file://../common | common | 0.1.10 | ## Values @@ -31,9 +31,11 @@ A Helm chart for gen3 sower | awsStsRegionalEndpoints | string | `"regional"` | AWS STS to issue temporary credentials to users and roles that make an AWS STS request. Values regional or global. | | commonLabels | map | `nil` | Will completely override the commonLabels defined in the common chart's _label_setup.tpl | | criticalService | string | `"false"` | Valid options are "true" or "false". If invalid option is set- the value will default to "false". | +| externalSecrets | map | `{"createK8sPelicanServiceSecret":false,"pelicanserviceG3auto":null}` | External Secrets settings. | +| externalSecrets.createK8sPelicanServiceSecret | string | `false` | Will create the Helm "manifestservice-g3auto" secret even if Secrets Manager is enabled. This is helpful if you are wanting to use External Secrets for some, but not all secrets. | +| externalSecrets.pelicanserviceG3auto | string | `nil` | Will override the name of the aws secrets manager secret. Default is "pelicanservice-g3auto" | | fullnameOverride | string | `""` | Override the full name of the deployment. | | gen3Namespace | string | `"default"` | Namespace to deploy the job. | -| global | map | `{"aws":{"awsAccessKeyId":null,"awsSecretAccessKey":null,"enabled":false},"ddEnabled":false,"dev":true,"dictionaryUrl":"https://s3.amazonaws.com/dictionary-artifacts/datadictionary/develop/schema.json","dispatcherJobNum":10,"environment":"default","hostname":"localhost","kubeBucket":"kube-gen3","logsBucket":"logs-gen3","netPolicy":true,"portalApp":"gitops","postgres":{"dbCreate":true,"master":{"host":null,"password":null,"port":"5432","username":"postgres"}},"publicDataSets":true,"revproxyArn":"arn:aws:acm:us-east-1:123456:certificate","tierAccessLevel":"libre"}` | Global configuration options. | | global.aws | map | `{"awsAccessKeyId":null,"awsSecretAccessKey":null,"enabled":false}` | AWS configuration | | global.aws.awsAccessKeyId | string | `nil` | Credentials for AWS stuff. | | global.aws.awsSecretAccessKey | string | `nil` | Credentials for AWS stuff. | @@ -41,15 +43,18 @@ A Helm chart for gen3 sower | global.ddEnabled | bool | `false` | Whether Datadog is enabled. | | global.dev | bool | `true` | Whether the deployment is for development purposes. | | global.dictionaryUrl | string | `"https://s3.amazonaws.com/dictionary-artifacts/datadictionary/develop/schema.json"` | URL of the data dictionary. | -| global.dispatcherJobNum | int | `10` | Number of dispatcher jobs. | +| global.dispatcherJobNum | int | `"10"` | Number of dispatcher jobs. | | global.environment | string | `"default"` | Environment name. This should be the same as vpcname if you're doing an AWS deployment. Currently this is being used to share ALB's if you have multiple namespaces. Might be used other places too. | +| global.externalSecrets | map | `{"deploy":false,"separateSecretStore":false}` | External Secrets settings. | +| global.externalSecrets.deploy | bool | `false` | Will use ExternalSecret resources to pull secrets from Secrets Manager instead of creating them locally. Be cautious as this will override any manifestservice secrets you have deployed. | +| global.externalSecrets.separateSecretStore | string | `false` | Will deploy a separate External Secret Store for this service. | | global.hostname | string | `"localhost"` | Hostname for the deployment. | | global.kubeBucket | string | `"kube-gen3"` | S3 bucket name for Kubernetes manifest files. | | global.logsBucket | string | `"logs-gen3"` | S3 bucket name for log files. | | global.netPolicy | bool | `true` | Whether network policies are enabled. | | global.portalApp | string | `"gitops"` | Portal application name. | -| global.postgres | map | `{"dbCreate":true,"master":{"host":null,"password":null,"port":"5432","username":"postgres"}}` | Postgres database configuration. | | global.postgres.dbCreate | bool | `true` | Whether the database should be created. | +| global.postgres.externalSecret | string | `""` | Name of external secret. Disabled if empty | | global.postgres.master | map | `{"host":null,"password":null,"port":"5432","username":"postgres"}` | Master credentials to postgres. This is going to be the default postgres server being used for each service, unless each service specifies their own postgres | | global.postgres.master.host | string | `nil` | hostname of postgres server | | global.postgres.master.password | string | `nil` | password for superuser in postgres. This is used to create or restore databases | @@ -77,6 +82,9 @@ A Helm chart for gen3 sower | resources.requests | map | `{"cpu":"100m","memory":"20Mi"}` | The amount of resources that the container requests | | resources.requests.cpu | string | `"100m"` | The amount of CPU requested | | resources.requests.memory | string | `"20Mi"` | The amount of memory requested | +| secrets | map | `{"awsAccessKeyId":null,"awsSecretAccessKey":null}` | Secret information for Usersync and External Secrets. | +| secrets.awsAccessKeyId | str | `nil` | AWS access key ID. Overrides global key. | +| secrets.awsSecretAccessKey | str | `nil` | AWS access key ID. Overrides global key. | | securityContext | map | `{}` | Security context for the containers in the pod | | selectorLabels | map | `nil` | Will completely override the selectorLabels defined in the common chart's _label_setup.tpl | | service | map | `{"port":80,"type":"ClusterIP"}` | Kubernetes service information. | @@ -96,7 +104,22 @@ A Helm chart for gen3 sower | sowerConfig[0].container.env[1].valueFrom.configMapKeyRef.name | string | `"manifest-global"` | | | sowerConfig[0].container.env[2].name | string | `"ROOT_NODE"` | | | sowerConfig[0].container.env[2].value | string | `"subject"` | | -| sowerConfig[0].container.image | string | `"quay.io/cdis/pelican-export:master"` | | +| sowerConfig[0].container.env[3].name | string | `"DB_HOST"` | | +| sowerConfig[0].container.env[3].valueFrom.secretKeyRef.key | string | `"host"` | | +| sowerConfig[0].container.env[3].valueFrom.secretKeyRef.name | string | `"peregrine-dbcreds"` | | +| sowerConfig[0].container.env[4].name | string | `"DB_DATABASE"` | | +| sowerConfig[0].container.env[4].valueFrom.secretKeyRef.key | string | `"database"` | | +| sowerConfig[0].container.env[4].valueFrom.secretKeyRef.name | string | `"peregrine-dbcreds"` | | +| sowerConfig[0].container.env[5].name | string | `"DB_USER"` | | +| sowerConfig[0].container.env[5].valueFrom.secretKeyRef.key | string | `"username"` | | +| sowerConfig[0].container.env[5].valueFrom.secretKeyRef.name | string | `"peregrine-dbcreds"` | | +| sowerConfig[0].container.env[6].name | string | `"DB_PASS"` | | +| sowerConfig[0].container.env[6].valueFrom.secretKeyRef.key | string | `"password"` | | +| sowerConfig[0].container.env[6].valueFrom.secretKeyRef.name | string | `"peregrine-dbcreds"` | | +| sowerConfig[0].container.env[7].name | string | `"SHEEPDOG"` | | +| sowerConfig[0].container.env[7].valueFrom.secretKeyRef.key | string | `"sheepdog"` | | +| sowerConfig[0].container.env[7].valueFrom.secretKeyRef.name | string | `"indexd-service-creds"` | | +| sowerConfig[0].container.image | string | `"quay.io/cdis/pelican-export:GPE-1252"` | | | sowerConfig[0].container.memory-limit | string | `"12Gi"` | | | sowerConfig[0].container.name | string | `"job-task"` | | | sowerConfig[0].container.pull_policy | string | `"Always"` | | @@ -104,16 +127,10 @@ A Helm chart for gen3 sower | sowerConfig[0].container.volumeMounts[0].name | string | `"pelican-creds-volume"` | | | sowerConfig[0].container.volumeMounts[0].readOnly | bool | `true` | | | sowerConfig[0].container.volumeMounts[0].subPath | string | `"config.json"` | | -| sowerConfig[0].container.volumeMounts[1].mountPath | string | `"/peregrine-creds.json"` | | -| sowerConfig[0].container.volumeMounts[1].name | string | `"peregrine-creds-volume"` | | -| sowerConfig[0].container.volumeMounts[1].readOnly | bool | `true` | | -| sowerConfig[0].container.volumeMounts[1].subPath | string | `"creds.json"` | | | sowerConfig[0].name | string | `"pelican-export"` | | | sowerConfig[0].restart_policy | string | `"Never"` | | | sowerConfig[0].volumes[0].name | string | `"pelican-creds-volume"` | | | sowerConfig[0].volumes[0].secret.secretName | string | `"pelicanservice-g3auto"` | | -| sowerConfig[0].volumes[1].name | string | `"peregrine-creds-volume"` | | -| sowerConfig[0].volumes[1].secret.secretName | string | `"peregrine-creds"` | | | sowerConfig[1].action | string | `"export-files"` | | | sowerConfig[1].container.cpu-limit | string | `"1"` | | | sowerConfig[1].container.env[0].name | string | `"DICTIONARY_URL"` | | @@ -126,7 +143,22 @@ A Helm chart for gen3 sower | sowerConfig[1].container.env[2].value | string | `"file"` | | | sowerConfig[1].container.env[3].name | string | `"EXTRA_NODES"` | | | sowerConfig[1].container.env[3].value | string | `""` | | -| sowerConfig[1].container.image | string | `"quay.io/cdis/pelican-export:master"` | | +| sowerConfig[1].container.env[4].name | string | `"DB_HOST"` | | +| sowerConfig[1].container.env[4].valueFrom.secretKeyRef.key | string | `"host"` | | +| sowerConfig[1].container.env[4].valueFrom.secretKeyRef.name | string | `"peregrine-dbcreds"` | | +| sowerConfig[1].container.env[5].name | string | `"DB_DATABASE"` | | +| sowerConfig[1].container.env[5].valueFrom.secretKeyRef.key | string | `"database"` | | +| sowerConfig[1].container.env[5].valueFrom.secretKeyRef.name | string | `"peregrine-dbcreds"` | | +| sowerConfig[1].container.env[6].name | string | `"DB_USER"` | | +| sowerConfig[1].container.env[6].valueFrom.secretKeyRef.key | string | `"username"` | | +| sowerConfig[1].container.env[6].valueFrom.secretKeyRef.name | string | `"peregrine-dbcreds"` | | +| sowerConfig[1].container.env[7].name | string | `"DB_PASS"` | | +| sowerConfig[1].container.env[7].valueFrom.secretKeyRef.key | string | `"password"` | | +| sowerConfig[1].container.env[7].valueFrom.secretKeyRef.name | string | `"peregrine-dbcreds"` | | +| sowerConfig[1].container.env[8].name | string | `"SHEEPDOG"` | | +| sowerConfig[1].container.env[8].valueFrom.secretKeyRef.key | string | `"sheepdog"` | | +| sowerConfig[1].container.env[8].valueFrom.secretKeyRef.name | string | `"indexd-service-creds"` | | +| sowerConfig[1].container.image | string | `"quay.io/cdis/pelican-export:GPE-1252"` | | | sowerConfig[1].container.memory-limit | string | `"12Gi"` | | | sowerConfig[1].container.name | string | `"job-task"` | | | sowerConfig[1].container.pull_policy | string | `"Always"` | | @@ -142,8 +174,6 @@ A Helm chart for gen3 sower | sowerConfig[1].restart_policy | string | `"Never"` | | | sowerConfig[1].volumes[0].name | string | `"pelican-creds-volume"` | | | sowerConfig[1].volumes[0].secret.secretName | string | `"pelicanservice-g3auto"` | | -| sowerConfig[1].volumes[1].name | string | `"peregrine-creds-volume"` | | -| sowerConfig[1].volumes[1].secret.secretName | string | `"peregrine-creds"` | | | strategy | map | `{"rollingUpdate":{"maxSurge":1,"maxUnavailable":0},"type":"RollingUpdate"}` | Rolling update deployment strategy | | strategy.rollingUpdate.maxSurge | int | `1` | Number of additional replicas to add during rollout. | | strategy.rollingUpdate.maxUnavailable | int | `0` | Maximum amount of pods that can be unavailable during the update. | @@ -151,5 +181,3 @@ A Helm chart for gen3 sower | volumeMounts | list | `[{"mountPath":"/sower_config.json","name":"sower-config","readOnly":true,"subPath":"sower_config.json"}]` | Volumes to mount to the container. | | volumes | list | `[{"configMap":{"items":[{"key":"json","path":"sower_config.json"}],"name":"manifest-sower"},"name":"sower-config"}]` | Volumes to attach to the container. | ----------------------------------------------- -Autogenerated from chart metadata using [helm-docs v1.11.0](https://github.com/norwoodj/helm-docs/releases/v1.11.0) diff --git a/helm/sower/templates/_helpers.tpl b/helm/sower/templates/_helpers.tpl index e9a7c298..1815359e 100644 --- a/helm/sower/templates/_helpers.tpl +++ b/helm/sower/templates/_helpers.tpl @@ -66,3 +66,10 @@ Create the name of the service account to use {{- default "default" .Values.serviceAccount.name }} {{- end }} {{- end }} + +{{/* + Pelicanservice g3 Auto Secrets Manager Name +*/}} +{{- define "pelicanservice-g3auto" -}} +{{- default "pelicanservice-g3auto" .Values.externalSecrets.pelicanserviceG3auto }} +{{- end }} \ No newline at end of file diff --git a/helm/sower/templates/aws-config.yaml b/helm/sower/templates/aws-config.yaml new file mode 100644 index 00000000..398770d3 --- /dev/null +++ b/helm/sower/templates/aws-config.yaml @@ -0,0 +1,3 @@ +{{- if or (.Values.secrets.awsSecretAccessKey) (.Values.global.aws.awsSecretAccessKey ) }} +{{ include "common.awsconfig" . }} +{{- end -}} \ No newline at end of file diff --git a/helm/sower/templates/external-secret.yaml b/helm/sower/templates/external-secret.yaml new file mode 100644 index 00000000..43132663 --- /dev/null +++ b/helm/sower/templates/external-secret.yaml @@ -0,0 +1,19 @@ +{{ if .Values.global.externalSecrets.deploy }} +apiVersion: external-secrets.io/v1beta1 +kind: ExternalSecret +metadata: + name: pelicanservice-g3auto +spec: + refreshInterval: 5m + secretStoreRef: + name: {{include "common.SecretStore" .}} + kind: SecretStore + target: + name: pelicanservice-g3auto + creationPolicy: Owner + data: + - secretKey: config.json + remoteRef: + #name of secret in secrets manager + key: {{include "pelicanservice-g3auto" .}} +{{- end }} \ No newline at end of file diff --git a/helm/sower/templates/pelican-creds.yaml b/helm/sower/templates/pelican-creds.yaml index cc6f526c..0d3420f5 100644 --- a/helm/sower/templates/pelican-creds.yaml +++ b/helm/sower/templates/pelican-creds.yaml @@ -1,3 +1,4 @@ +{{- if or (not .Values.global.externalSecrets.deploy) (and .Values.global.externalSecrets.deploy .Values.externalSecrets.createK8sPelicanServiceSecret) }} apiVersion: v1 kind: Secret metadata: @@ -5,11 +6,12 @@ metadata: type: Opaque {{- if .Values.global.aws.enabled }} stringData: - config.json: |- -{ - "manifest_bucket_name": "{{ .Values.pelican.bucket }}", - "hostname": "{{ .Values.global.hostname }}", - "aws_access_key_id": "{{ .Values.global.aws.pelican_user.access_key }}", - "aws_secret_access_key": "{{ .Values.global.aws.pelican_user.access_secret }}" -} + config.json: | + { + "manifest_bucket_name": "{{ .Values.pelican.bucket }}", + "hostname": "{{ .Values.global.hostname }}", + "aws_access_key_id": "{{ .Values.secrets.awsAccessKeyId | default .Values.global.aws.awsAccessKeyId }}", + "aws_secret_access_key": "{{ .Values.secrets.awsSecretAccessKey | default .Values.global.aws.awsSecretAccessKey }}" + } {{- end }} +{{- end }} \ No newline at end of file diff --git a/helm/sower/templates/secret-store.yaml b/helm/sower/templates/secret-store.yaml new file mode 100644 index 00000000..771c7760 --- /dev/null +++ b/helm/sower/templates/secret-store.yaml @@ -0,0 +1,3 @@ +{{ if .Values.global.externalSecrets.separateSecretStore }} +{{ include "common.secretstore" . }} +{{- end }} \ No newline at end of file diff --git a/helm/sower/values.yaml b/helm/sower/values.yaml index bb327782..48f36db2 100644 --- a/helm/sower/values.yaml +++ b/helm/sower/values.yaml @@ -2,7 +2,8 @@ # This is a YAML-formatted file. # Declare variables to be passed into your templates. -# -- (map) Global configuration options. + +# Global configuration global: # -- (map) AWS configuration aws: @@ -14,10 +15,12 @@ global: awsSecretAccessKey: # -- (bool) Whether the deployment is for development purposes. dev: true - # -- (map) Postgres database configuration. + postgres: # -- (bool) Whether the database should be created. dbCreate: true + # -- (string) Name of external secret. Disabled if empty + externalSecret: "" # -- (map) Master credentials to postgres. This is going to be the default postgres server being used for each service, unless each service specifies their own postgres master: # -- (string) hostname of postgres server @@ -49,9 +52,29 @@ global: # -- (bool) Whether network policies are enabled. netPolicy: true # -- (int) Number of dispatcher jobs. - dispatcherJobNum: 10 + dispatcherJobNum: "10" # -- (bool) Whether Datadog is enabled. ddEnabled: false + # -- (map) External Secrets settings. + externalSecrets: + # -- (bool) Will use ExternalSecret resources to pull secrets from Secrets Manager instead of creating them locally. Be cautious as this will override any manifestservice secrets you have deployed. + deploy: false + # -- (string) Will deploy a separate External Secret Store for this service. + separateSecretStore: false + +# -- (map) External Secrets settings. +externalSecrets: + # -- (string) Will create the Helm "manifestservice-g3auto" secret even if Secrets Manager is enabled. This is helpful if you are wanting to use External Secrets for some, but not all secrets. + createK8sPelicanServiceSecret: false + # -- (string) Will override the name of the aws secrets manager secret. Default is "pelicanservice-g3auto" + pelicanserviceG3auto: + +# -- (map) Secret information for Usersync and External Secrets. +secrets: + # -- (str) AWS access key ID. Overrides global key. + awsAccessKeyId: + # -- (str) AWS access key ID. Overrides global key. + awsSecretAccessKey: # -- (int) Number of replicas for the deployment. replicaCount: 1 @@ -187,7 +210,7 @@ sowerConfig: action: export container: name: job-task - image: quay.io/cdis/pelican-export:master + image: quay.io/cdis/pelican-export:GPE-1252 pull_policy: Always env: - name: DICTIONARY_URL @@ -202,30 +225,48 @@ sowerConfig: key: hostname - name: ROOT_NODE value: subject + - name: DB_HOST + valueFrom: + secretKeyRef: + name: peregrine-dbcreds + key: host + - name: DB_DATABASE + valueFrom: + secretKeyRef: + name: peregrine-dbcreds + key: database + - name: DB_USER + valueFrom: + secretKeyRef: + name: peregrine-dbcreds + key: username + - name: DB_PASS + valueFrom: + secretKeyRef: + name: peregrine-dbcreds + key: password + - name: SHEEPDOG + valueFrom: + secretKeyRef: + name: indexd-service-creds + key: sheepdog volumeMounts: - name: pelican-creds-volume readOnly: true mountPath: "/pelican-creds.json" subPath: config.json - - name: peregrine-creds-volume - readOnly: true - mountPath: "/peregrine-creds.json" - subPath: creds.json cpu-limit: '1' memory-limit: 12Gi volumes: - name: pelican-creds-volume secret: secretName: pelicanservice-g3auto - - name: peregrine-creds-volume - secret: - secretName: peregrine-creds restart_policy: Never - name: pelican-export-files action: export-files container: name: job-task - image: quay.io/cdis/pelican-export:master + image: quay.io/cdis/pelican-export:GPE-1252 pull_policy: Always env: - name: DICTIONARY_URL @@ -242,6 +283,31 @@ sowerConfig: value: file - name: EXTRA_NODES value: '' + - name: DB_HOST + valueFrom: + secretKeyRef: + name: peregrine-dbcreds + key: host + - name: DB_DATABASE + valueFrom: + secretKeyRef: + name: peregrine-dbcreds + key: database + - name: DB_USER + valueFrom: + secretKeyRef: + name: peregrine-dbcreds + key: username + - name: DB_PASS + valueFrom: + secretKeyRef: + name: peregrine-dbcreds + key: password + - name: SHEEPDOG + valueFrom: + secretKeyRef: + name: indexd-service-creds + key: sheepdog volumeMounts: - name: pelican-creds-volume readOnly: true @@ -257,9 +323,6 @@ sowerConfig: - name: pelican-creds-volume secret: secretName: pelicanservice-g3auto - - name: peregrine-creds-volume - secret: - secretName: peregrine-creds restart_policy: Never diff --git a/helm/ssjdispatcher/Chart.yaml b/helm/ssjdispatcher/Chart.yaml index 4f97d26b..ac668287 100644 --- a/helm/ssjdispatcher/Chart.yaml +++ b/helm/ssjdispatcher/Chart.yaml @@ -15,7 +15,7 @@ type: application # This is the chart version. This version number should be incremented each time you make changes # to the chart and its templates, including the app version. # Versions are expected to follow Semantic Versioning (https://semver.org/) -version: 0.1.7 +version: 0.1.9 # This is the version number of the application being deployed. This version number should be # incremented each time you make changes to the application. Versions are not expected to @@ -25,5 +25,5 @@ appVersion: "master" dependencies: - name: common - version: 0.1.8 + version: 0.1.10 repository: file://../common diff --git a/helm/ssjdispatcher/README.md b/helm/ssjdispatcher/README.md index e09ea9f2..3bb1ab0a 100644 --- a/helm/ssjdispatcher/README.md +++ b/helm/ssjdispatcher/README.md @@ -1,6 +1,6 @@ # ssjdispatcher -![Version: 0.1.7](https://img.shields.io/badge/Version-0.1.7-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: master](https://img.shields.io/badge/AppVersion-master-informational?style=flat-square) +![Version: 0.1.9](https://img.shields.io/badge/Version-0.1.9-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: master](https://img.shields.io/badge/AppVersion-master-informational?style=flat-square) A Helm chart for gen3 ssjdispatcher @@ -8,7 +8,7 @@ A Helm chart for gen3 ssjdispatcher | Repository | Name | Version | |------------|------|---------| -| file://../common | common | 0.1.8 | +| file://../common | common | 0.1.10 | ## Values @@ -37,7 +37,6 @@ A Helm chart for gen3 ssjdispatcher | dispatcherJobNum | string | `"10"` | Ssjdispater job number. | | fullnameOverride | string | `""` | Override the full name of the deployment. | | gen3Namespace | string | `"default"` | Namespace to deploy the job. | -| global | map | `{"aws":{"awsAccessKeyId":null,"awsSecretAccessKey":null,"enabled":false},"ddEnabled":false,"dev":true,"dictionaryUrl":"https://s3.amazonaws.com/dictionary-artifacts/datadictionary/develop/schema.json","dispatcherJobNum":10,"environment":"default","hostname":"localhost","kubeBucket":"kube-gen3","logsBucket":"logs-gen3","minAvialable":1,"netPolicy":true,"pdb":false,"portalApp":"gitops","postgres":{"dbCreate":true,"master":{"host":null,"password":null,"port":"5432","username":"postgres"}},"publicDataSets":true,"revproxyArn":"arn:aws:acm:us-east-1:123456:certificate","tierAccessLevel":"libre"}` | Global configuration options. | | global.aws | map | `{"awsAccessKeyId":null,"awsSecretAccessKey":null,"enabled":false}` | AWS configuration | | global.aws.awsAccessKeyId | string | `nil` | Credentials for AWS stuff. | | global.aws.awsSecretAccessKey | string | `nil` | Credentials for AWS stuff. | @@ -45,7 +44,7 @@ A Helm chart for gen3 ssjdispatcher | global.ddEnabled | bool | `false` | Whether Datadog is enabled. | | global.dev | bool | `true` | Whether the deployment is for development purposes. | | global.dictionaryUrl | string | `"https://s3.amazonaws.com/dictionary-artifacts/datadictionary/develop/schema.json"` | URL of the data dictionary. | -| global.dispatcherJobNum | int | `10` | Number of dispatcher jobs. | +| global.dispatcherJobNum | int | `"10"` | Number of dispatcher jobs. | | global.environment | string | `"default"` | Environment name. This should be the same as vpcname if you're doing an AWS deployment. Currently this is being used to share ALB's if you have multiple namespaces. Might be used other places too. | | global.hostname | string | `"localhost"` | Hostname for the deployment. | | global.kubeBucket | string | `"kube-gen3"` | S3 bucket name for Kubernetes manifest files. | @@ -54,8 +53,8 @@ A Helm chart for gen3 ssjdispatcher | global.netPolicy | bool | `true` | Whether network policies are enabled. | | global.pdb | bool | `false` | If the service will be deployed with a Pod Disruption Budget. Note- you need to have more than 2 replicas for the pdb to be deployed. | | global.portalApp | string | `"gitops"` | Portal application name. | -| global.postgres | map | `{"dbCreate":true,"master":{"host":null,"password":null,"port":"5432","username":"postgres"}}` | Postgres database configuration. | | global.postgres.dbCreate | bool | `true` | Whether the database should be created. | +| global.postgres.externalSecret | string | `""` | Name of external secret. Disabled if empty | | global.postgres.master | map | `{"host":null,"password":null,"port":"5432","username":"postgres"}` | Master credentials to postgres. This is going to be the default postgres server being used for each service, unless each service specifies their own postgres | | global.postgres.master.host | string | `nil` | hostname of postgres server | | global.postgres.master.password | string | `nil` | password for superuser in postgres. This is used to create or restore databases | @@ -113,5 +112,3 @@ A Helm chart for gen3 ssjdispatcher | volumeMounts | list | `[{"mountPath":"/credentials.json","name":"ssjdispatcher-creds-volume","readOnly":true,"subPath":"credentials.json"}]` | Volumes to mount to the container. | | volumes | list | `[{"name":"ssjdispatcher-creds-volume","secret":{"secretName":"ssjdispatcher-creds"}}]` | Volumes to attach to the container. | ----------------------------------------------- -Autogenerated from chart metadata using [helm-docs v1.11.0](https://github.com/norwoodj/helm-docs/releases/v1.11.0) diff --git a/helm/ssjdispatcher/values.yaml b/helm/ssjdispatcher/values.yaml index d1b028d7..74ed990b 100644 --- a/helm/ssjdispatcher/values.yaml +++ b/helm/ssjdispatcher/values.yaml @@ -2,7 +2,8 @@ # This is a YAML-formatted file. # Declare variables to be passed into your templates. -# -- (map) Global configuration options. + +# Global configuration global: # -- (map) AWS configuration aws: @@ -14,10 +15,12 @@ global: awsSecretAccessKey: # -- (bool) Whether the deployment is for development purposes. dev: true - # -- (map) Postgres database configuration. + postgres: # -- (bool) Whether the database should be created. dbCreate: true + # -- (string) Name of external secret. Disabled if empty + externalSecret: "" # -- (map) Master credentials to postgres. This is going to be the default postgres server being used for each service, unless each service specifies their own postgres master: # -- (string) hostname of postgres server @@ -49,7 +52,7 @@ global: # -- (bool) Whether network policies are enabled. netPolicy: true # -- (int) Number of dispatcher jobs. - dispatcherJobNum: 10 + dispatcherJobNum: "10" # -- (bool) Whether Datadog is enabled. ddEnabled: false # -- (bool) If the service will be deployed with a Pod Disruption Budget. Note- you need to have more than 2 replicas for the pdb to be deployed. diff --git a/helm/wts/Chart.yaml b/helm/wts/Chart.yaml index c572f64a..6d9533e4 100644 --- a/helm/wts/Chart.yaml +++ b/helm/wts/Chart.yaml @@ -15,7 +15,7 @@ type: application # This is the chart version. This version number should be incremented each time you make changes # to the chart and its templates, including the app version. # Versions are expected to follow Semantic Versioning (https://semver.org/) -version: 0.1.11 +version: 0.1.13 # This is the version number of the application being deployed. This version number should be # incremented each time you make changes to the application. Versions are not expected to @@ -25,7 +25,7 @@ appVersion: "master" dependencies: - name: common - version: 0.1.8 + version: 0.1.10 repository: file://../common - name: postgresql version: 11.9.13 diff --git a/helm/wts/README.md b/helm/wts/README.md index e4e115ea..da26c055 100644 --- a/helm/wts/README.md +++ b/helm/wts/README.md @@ -1,6 +1,6 @@ # wts -![Version: 0.1.11](https://img.shields.io/badge/Version-0.1.11-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: master](https://img.shields.io/badge/AppVersion-master-informational?style=flat-square) +![Version: 0.1.13](https://img.shields.io/badge/Version-0.1.13-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: master](https://img.shields.io/badge/AppVersion-master-informational?style=flat-square) A Helm chart for gen3 workspace token service @@ -8,7 +8,7 @@ A Helm chart for gen3 workspace token service | Repository | Name | Version | |------------|------|---------| -| file://../common | common | 0.1.8 | +| file://../common | common | 0.1.10 | | https://charts.bitnami.com/bitnami | postgresql | 11.9.13 | ## Values @@ -26,8 +26,9 @@ A Helm chart for gen3 workspace token service | datadogLogsInjection | bool | `true` | If enabled, the Datadog Agent will automatically inject Datadog-specific metadata into your application logs. | | datadogProfilingEnabled | bool | `true` | If enabled, the Datadog Agent will collect profiling data for your application using the Continuous Profiler. This data can be used to identify performance bottlenecks and optimize your application. | | datadogTraceSampleRate | int | `1` | A value between 0 and 1, that represents the percentage of requests that will be traced. For example, a value of 0.5 means that 50% of requests will be traced. | +| externalSecrets | map | `{"dbcreds":null}` | External Secrets settings. | +| externalSecrets.dbcreds | string | `nil` | Will override the name of the aws secrets manager secret. Default is "Values.global.environment-.Chart.Name-creds" | | fullnameOverride | string | `""` | Override the full name of the deployment. | -| global | map | `{"aws":{"awsAccessKeyId":null,"awsSecretAccessKey":null,"enabled":false},"ddEnabled":false,"dev":true,"dictionaryUrl":"https://s3.amazonaws.com/dictionary-artifacts/datadictionary/develop/schema.json","dispatcherJobNum":10,"environment":"default","hostname":"localhost","kubeBucket":"kube-gen3","logsBucket":"logs-gen3","minAvialable":1,"netPolicy":true,"pdb":false,"portalApp":"gitops","postgres":{"dbCreate":true,"master":{"host":null,"password":null,"port":"5432","username":"postgres"}},"publicDataSets":true,"revproxyArn":"arn:aws:acm:us-east-1:123456:certificate","tierAccessLevel":"libre"}` | Global configuration options. | | global.aws | map | `{"awsAccessKeyId":null,"awsSecretAccessKey":null,"enabled":false}` | AWS configuration | | global.aws.awsAccessKeyId | string | `nil` | Credentials for AWS stuff. | | global.aws.awsSecretAccessKey | string | `nil` | Credentials for AWS stuff. | @@ -35,8 +36,11 @@ A Helm chart for gen3 workspace token service | global.ddEnabled | bool | `false` | Whether Datadog is enabled. | | global.dev | bool | `true` | Whether the deployment is for development purposes. | | global.dictionaryUrl | string | `"https://s3.amazonaws.com/dictionary-artifacts/datadictionary/develop/schema.json"` | URL of the data dictionary. | -| global.dispatcherJobNum | int | `10` | Number of dispatcher jobs. | +| global.dispatcherJobNum | int | `"10"` | Number of dispatcher jobs. | | global.environment | string | `"default"` | Environment name. This should be the same as vpcname if you're doing an AWS deployment. Currently this is being used to share ALB's if you have multiple namespaces. Might be used other places too. | +| global.externalSecrets | map | `{"deploy":false,"separateSecretStore":false}` | External Secrets settings. | +| global.externalSecrets.deploy | bool | `false` | Will use ExternalSecret resources to pull secrets from Secrets Manager instead of creating them locally. Be cautious as this will override any wts secrets you have deployed. | +| global.externalSecrets.separateSecretStore | string | `false` | Will deploy a separate External Secret Store for this service. | | global.hostname | string | `"localhost"` | Hostname for the deployment. | | global.kubeBucket | string | `"kube-gen3"` | S3 bucket name for Kubernetes manifest files. | | global.logsBucket | string | `"logs-gen3"` | S3 bucket name for log files. | @@ -44,8 +48,8 @@ A Helm chart for gen3 workspace token service | global.netPolicy | bool | `true` | Whether network policies are enabled. | | global.pdb | bool | `false` | If the service will be deployed with a Pod Disruption Budget. Note- you need to have more than 2 replicas for the pdb to be deployed. | | global.portalApp | string | `"gitops"` | Portal application name. | -| global.postgres | map | `{"dbCreate":true,"master":{"host":null,"password":null,"port":"5432","username":"postgres"}}` | Postgres database configuration. | | global.postgres.dbCreate | bool | `true` | Whether the database should be created. | +| global.postgres.externalSecret | string | `""` | Name of external secret. Disabled if empty | | global.postgres.master | map | `{"host":null,"password":null,"port":"5432","username":"postgres"}` | Master credentials to postgres. This is going to be the default postgres server being used for each service, unless each service specifies their own postgres | | global.postgres.master.host | string | `nil` | hostname of postgres server | | global.postgres.master.password | string | `nil` | password for superuser in postgres. This is used to create or restore databases | @@ -86,7 +90,9 @@ A Helm chart for gen3 workspace token service | resources.requests.cpu | string | `0.2` | The amount of CPU requested | | resources.requests.memory | string | `"120Mi"` | The amount of memory requested | | roleName | string | `"workspace-token-service"` | Name of the role to be used for the role binding. | -| secrets | map | `{"external_oidc":null}` | Values for wts secret. | +| secrets | map | `{"awsAccessKeyId":null,"awsSecretAccessKey":null,"external_oidc":null}` | Values for wts secret and keys for External Secrets. | +| secrets.awsAccessKeyId | str | `nil` | AWS access key ID. Overrides global key. | +| secrets.awsSecretAccessKey | str | `nil` | AWS secret access key ID. Overrides global key. | | securityContext | map | `{}` | Security context for the containers in the pod | | selectorLabels | map | `nil` | Will completely override the selectorLabels defined in the common chart's _label_setup.tpl | | service | map | `{"httpPort":80,"httpsPort":443,"type":"ClusterIP"}` | Configuration for the service | @@ -104,5 +110,3 @@ A Helm chart for gen3 workspace token service | tolerations | list | `[]` | Tolerations for the pods | | volumeMounts | list | `[{"mountPath":"/var/www/wts/appcreds.json","name":"wts-secret","readOnly":true,"subPath":"appcreds.json"},{"mountPath":"/wts/deployment/wsgi/gunicorn.conf.py","name":"wsgi-config","subPath":"gunicorn.conf.py"}]` | Volumes to mount to the container. | ----------------------------------------------- -Autogenerated from chart metadata using [helm-docs v1.11.0](https://github.com/norwoodj/helm-docs/releases/v1.11.0) diff --git a/helm/wts/templates/_helpers.tpl b/helm/wts/templates/_helpers.tpl index f8cebb83..a8a094c0 100644 --- a/helm/wts/templates/_helpers.tpl +++ b/helm/wts/templates/_helpers.tpl @@ -78,4 +78,4 @@ Create the name of the service account to use {{- else }} {{- default .Values.postgres.password }} {{- end }} -{{- end }} \ No newline at end of file +{{- end }} diff --git a/helm/wts/templates/aws-config.yaml b/helm/wts/templates/aws-config.yaml new file mode 100644 index 00000000..398770d3 --- /dev/null +++ b/helm/wts/templates/aws-config.yaml @@ -0,0 +1,3 @@ +{{- if or (.Values.secrets.awsSecretAccessKey) (.Values.global.aws.awsSecretAccessKey ) }} +{{ include "common.awsconfig" . }} +{{- end -}} \ No newline at end of file diff --git a/helm/wts/templates/db-init.yaml b/helm/wts/templates/db-init.yaml index abbefb6e..d99ca1b2 100644 --- a/helm/wts/templates/db-init.yaml +++ b/helm/wts/templates/db-init.yaml @@ -1,6 +1,6 @@ -{{ include "common.db_setup_job" . }} ---- {{ include "common.db-secret" . }} --- +{{ include "common.db_setup_job" . }} +--- {{ include "common.db_setup_sa" . }} --- diff --git a/helm/wts/templates/external-secret.yaml b/helm/wts/templates/external-secret.yaml new file mode 100644 index 00000000..70c278fe --- /dev/null +++ b/helm/wts/templates/external-secret.yaml @@ -0,0 +1 @@ +{{ include "common.externalSecret.db" . }} \ No newline at end of file diff --git a/helm/wts/templates/secret-store.yaml b/helm/wts/templates/secret-store.yaml new file mode 100644 index 00000000..771c7760 --- /dev/null +++ b/helm/wts/templates/secret-store.yaml @@ -0,0 +1,3 @@ +{{ if .Values.global.externalSecrets.separateSecretStore }} +{{ include "common.secretstore" . }} +{{- end }} \ No newline at end of file diff --git a/helm/wts/values.yaml b/helm/wts/values.yaml index fe1dcbf7..508f4a2f 100644 --- a/helm/wts/values.yaml +++ b/helm/wts/values.yaml @@ -2,7 +2,8 @@ # This is a YAML-formatted file. # Declare variables to be passed into your templates. -# -- (map) Global configuration options. + +# Global configuration global: # -- (map) AWS configuration aws: @@ -14,10 +15,12 @@ global: awsSecretAccessKey: # -- (bool) Whether the deployment is for development purposes. dev: true - # -- (map) Postgres database configuration. + postgres: # -- (bool) Whether the database should be created. dbCreate: true + # -- (string) Name of external secret. Disabled if empty + externalSecret: "" # -- (map) Master credentials to postgres. This is going to be the default postgres server being used for each service, unless each service specifies their own postgres master: # -- (string) hostname of postgres server @@ -49,13 +52,24 @@ global: # -- (bool) Whether network policies are enabled. netPolicy: true # -- (int) Number of dispatcher jobs. - dispatcherJobNum: 10 + dispatcherJobNum: "10" # -- (bool) Whether Datadog is enabled. ddEnabled: false # -- (bool) If the service will be deployed with a Pod Disruption Budget. Note- you need to have more than 2 replicas for the pdb to be deployed. pdb: false # -- (int) The minimum amount of pods that are available at all times if the PDB is deployed. minAvialable: 1 + # -- (map) External Secrets settings. + externalSecrets: + # -- (bool) Will use ExternalSecret resources to pull secrets from Secrets Manager instead of creating them locally. Be cautious as this will override any wts secrets you have deployed. + deploy: false + # -- (string) Will deploy a separate External Secret Store for this service. + separateSecretStore: false + +# -- (map) External Secrets settings. +externalSecrets: + # -- (string) Will override the name of the aws secrets manager secret. Default is "Values.global.environment-.Chart.Name-creds" + dbcreds: # -- (map) Postgres database configuration. If db does not exist in postgres cluster and dbCreate is set ot true then these databases will be created for you postgres: @@ -205,8 +219,12 @@ affinity: {} # -- (string) Name of the role to be used for the role binding. roleName: workspace-token-service -# -- (map) Values for wts secret. +# -- (map) Values for wts secret and keys for External Secrets. secrets: + # -- (str) AWS access key ID. Overrides global key. + awsAccessKeyId: + # -- (str) AWS secret access key ID. Overrides global key. + awsSecretAccessKey: external_oidc: # - base_url: # oidc_client_id: