├── LICENSE ├── README.md ├── cert-manager ├── cluster-issuer.yaml ├── crds.yaml ├── deployment.yaml ├── rbac.yaml └── sa.yaml ├── external-dns ├── deployment.yaml ├── rbac.yaml └── sa.yaml ├── keycloak ├── cm.yaml ├── ingress.yaml ├── kustomization.yaml ├── realm-export.json ├── services.yaml └── statefulset.yaml ├── kustomization.yaml ├── logging ├── curator │ ├── action_file.yaml │ ├── config.yaml │ ├── cronjob.yaml │ └── kustomization.yaml ├── elasticsearch │ ├── java.security │ ├── kustomization.yaml │ ├── rbac.yaml │ ├── sa.yaml │ ├── service.yaml │ └── statefulset.yaml ├── fluentd │ ├── containers.input.conf │ ├── ds.yaml │ ├── fluentd.conf │ ├── kustomization.yaml │ ├── monitoring.conf │ ├── rbac.yaml │ ├── sa.yaml │ ├── system.conf │ └── system.input.conf ├── kibana │ ├── deployment.yaml │ ├── ingress.yaml │ └── service.yaml └── kustomization.yaml ├── metrics ├── alertmanager │ ├── cm.yaml │ ├── service.yaml │ └── statefulset.yaml ├── grafana │ ├── cm.yaml │ ├── ingress.yaml │ ├── service.yaml │ └── statefulset.yaml ├── kube-state-metrics │ ├── deployment.yaml │ ├── rbac.yaml │ └── sa.yaml ├── kustomization.yaml ├── node-exporter │ └── ds.yaml └── prometheus │ ├── cm.yaml │ ├── ingress.yaml │ ├── rbac.yaml │ ├── sa.yaml │ ├── service.yaml │ └── statefulset.yaml ├── nginx-ingress ├── configmaps.yaml ├── deployment.yaml ├── hpa.yaml ├── kustomization.yaml ├── rbac.yaml ├── sa.yaml └── service.yaml ├── oauth2-proxy ├── deployment.yaml ├── hpa.yaml └── service.yaml └── postgresql ├── deployment.yaml ├── kustomization.yaml ├── pvc.yaml └── service.yaml /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [2019] [innoQ Schweiz GmbH] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Kube-Platform Base 2 | 3 | Base YAMLs for usage with [kustomize](https://github.com/kubernetes-sigs/kustomize) and a *-overlay -------------------------------------------------------------------------------- /cert-manager/cluster-issuer.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: cert-manager.io/v1alpha2 2 | kind: ClusterIssuer 3 | metadata: 4 | name: letsencrypt-staging 5 | spec: 6 | acme: 7 | email: someone@innoq.com 8 | solvers: 9 | - http01: 10 | ingress: 11 | class: nginx 12 | privateKeySecretRef: 13 | key: "" 14 | name: letsencrypt-staging 15 | server: https://acme-staging-v02.api.letsencrypt.org/directory 16 | 17 | --- 18 | 19 | apiVersion: cert-manager.io/v1alpha2 20 | kind: ClusterIssuer 21 | metadata: 22 | name: letsencrypt-prod 23 | spec: 24 | acme: 25 | email: someone@innoq.com 26 | solvers: 27 | - http01: 28 | ingress: 29 | class: nginx 30 | privateKeySecretRef: 31 | key: "" 32 | name: letsencrypt-prod 33 | server: https://acme-v02.api.letsencrypt.org/directory 34 | -------------------------------------------------------------------------------- /cert-manager/deployment.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | labels: 5 | name: cert-manager 6 | name: cert-manager 7 | spec: 8 | replicas: 1 9 | selector: 10 | matchLabels: 11 | name: cert-manager 12 | template: 13 | metadata: 14 | annotations: 15 | prometheus.io/path: /metrics 16 | prometheus.io/port: "9402" 17 | prometheus.io/scrape: "true" 18 | labels: 19 | name: cert-manager 20 | spec: 21 | serviceAccountName: cert-manager 22 | containers: 23 | - name: cert-manager 24 | args: 25 | - --v=2 26 | - --cluster-resource-namespace=$(POD_NAMESPACE) 27 | - --default-issuer-kind=ClusterIssuer 28 | - --default-issuer-name=$(CLUSTER_ISSUER_NAME) 29 | - --leader-election-namespace=$(POD_NAMESPACE) 30 | - --webhook-namespace=$(POD_NAMESPACE) 31 | env: 32 | - name: POD_NAMESPACE 33 | valueFrom: 34 | fieldRef: 35 | apiVersion: v1 36 | fieldPath: metadata.namespace 37 | image: quay.io/jetstack/cert-manager-controller:v0.13.1 38 | ports: 39 | - containerPort: 9402 40 | name: prometheus 41 | protocol: TCP 42 | resources: 43 | requests: 44 | cpu: 10m 45 | memory: 32Mi 46 | -------------------------------------------------------------------------------- /cert-manager/rbac.yaml: -------------------------------------------------------------------------------- 1 | 2 | # Source: cert-manager/templates/rbac.yaml 3 | apiVersion: rbac.authorization.k8s.io/v1beta1 4 | kind: Role 5 | metadata: 6 | name: cert-manager:leaderelection 7 | namespace: kubeplatform # kube-system 8 | labels: 9 | app: cert-manager 10 | rules: 11 | # Used for leader election by the controller 12 | # TODO: refine the permission to *just* the leader election configmap 13 | - apiGroups: [""] 14 | resources: ["configmaps"] 15 | verbs: ["get", "create", "update", "patch"] 16 | 17 | --- 18 | 19 | # grant cert-manager permission to manage the leaderelection configmap in the 20 | # leader election namespace 21 | apiVersion: rbac.authorization.k8s.io/v1beta1 22 | kind: RoleBinding 23 | metadata: 24 | name: cert-manager:leaderelection 25 | namespace: kubeplatform # kube-system 26 | labels: 27 | app: cert-manager 28 | roleRef: 29 | apiGroup: rbac.authorization.k8s.io 30 | kind: Role 31 | name: cert-manager:leaderelection 32 | subjects: 33 | - apiGroup: "" 34 | kind: ServiceAccount 35 | name: cert-manager 36 | namespace: kubeplatform # cert-manager 37 | 38 | --- 39 | 40 | # Issuer controller role 41 | apiVersion: rbac.authorization.k8s.io/v1beta1 42 | kind: ClusterRole 43 | metadata: 44 | name: cert-manager-controller-issuers 45 | labels: 46 | app: cert-manager 47 | rules: 48 | - apiGroups: ["cert-manager.io"] 49 | resources: ["issuers", "issuers/status"] 50 | verbs: ["update"] 51 | - apiGroups: ["cert-manager.io"] 52 | resources: ["issuers"] 53 | verbs: ["get", "list", "watch"] 54 | - apiGroups: [""] 55 | resources: ["secrets"] 56 | verbs: ["get", "list", "watch", "create", "update", "delete"] 57 | - apiGroups: [""] 58 | resources: ["events"] 59 | verbs: ["create", "patch"] 60 | 61 | --- 62 | 63 | # ClusterIssuer controller role 64 | apiVersion: rbac.authorization.k8s.io/v1beta1 65 | kind: ClusterRole 66 | metadata: 67 | name: cert-manager-controller-clusterissuers 68 | labels: 69 | app: cert-manager 70 | rules: 71 | - apiGroups: ["cert-manager.io"] 72 | resources: ["clusterissuers", "clusterissuers/status"] 73 | verbs: ["update"] 74 | - apiGroups: ["cert-manager.io"] 75 | resources: ["clusterissuers"] 76 | verbs: ["get", "list", "watch"] 77 | - apiGroups: [""] 78 | resources: ["secrets"] 79 | verbs: ["get", "list", "watch", "create", "update", "delete"] 80 | - apiGroups: [""] 81 | resources: ["events"] 82 | verbs: ["create", "patch"] 83 | 84 | --- 85 | 86 | # Certificates controller role 87 | apiVersion: rbac.authorization.k8s.io/v1beta1 88 | kind: ClusterRole 89 | metadata: 90 | name: cert-manager-controller-certificates 91 | labels: 92 | app: cert-manager 93 | rules: 94 | - apiGroups: ["cert-manager.io"] 95 | resources: ["certificates", "certificates/status", "certificaterequests", "certificaterequests/status"] 96 | verbs: ["update"] 97 | - apiGroups: ["cert-manager.io"] 98 | resources: ["certificates", "certificaterequests", "clusterissuers", "issuers"] 99 | verbs: ["get", "list", "watch"] 100 | # We require these rules to support users with the OwnerReferencesPermissionEnforcement 101 | # admission controller enabled: 102 | # https://kubernetes.io/docs/reference/access-authn-authz/admission-controllers/#ownerreferencespermissionenforcement 103 | - apiGroups: ["cert-manager.io"] 104 | resources: ["certificates/finalizers", "certificaterequests/finalizers"] 105 | verbs: ["update"] 106 | - apiGroups: ["acme.cert-manager.io"] 107 | resources: ["orders"] 108 | verbs: ["create", "delete", "get", "list", "watch"] 109 | - apiGroups: [""] 110 | resources: ["secrets"] 111 | verbs: ["get", "list", "watch", "create", "update", "delete"] 112 | - apiGroups: [""] 113 | resources: ["events"] 114 | verbs: ["create", "patch"] 115 | 116 | --- 117 | 118 | # Orders controller role 119 | apiVersion: rbac.authorization.k8s.io/v1beta1 120 | kind: ClusterRole 121 | metadata: 122 | name: cert-manager-controller-orders 123 | labels: 124 | app: cert-manager 125 | rules: 126 | - apiGroups: ["acme.cert-manager.io"] 127 | resources: ["orders", "orders/status"] 128 | verbs: ["update"] 129 | - apiGroups: ["acme.cert-manager.io"] 130 | resources: ["orders", "challenges"] 131 | verbs: ["get", "list", "watch"] 132 | - apiGroups: ["cert-manager.io"] 133 | resources: ["clusterissuers", "issuers"] 134 | verbs: ["get", "list", "watch"] 135 | - apiGroups: ["acme.cert-manager.io"] 136 | resources: ["challenges"] 137 | verbs: ["create", "delete"] 138 | # We require these rules to support users with the OwnerReferencesPermissionEnforcement 139 | # admission controller enabled: 140 | # https://kubernetes.io/docs/reference/access-authn-authz/admission-controllers/#ownerreferencespermissionenforcement 141 | - apiGroups: ["acme.cert-manager.io"] 142 | resources: ["orders/finalizers"] 143 | verbs: ["update"] 144 | - apiGroups: [""] 145 | resources: ["secrets"] 146 | verbs: ["get", "list", "watch"] 147 | - apiGroups: [""] 148 | resources: ["events"] 149 | verbs: ["create", "patch"] 150 | 151 | --- 152 | 153 | # Challenges controller role 154 | apiVersion: rbac.authorization.k8s.io/v1beta1 155 | kind: ClusterRole 156 | metadata: 157 | name: cert-manager-controller-challenges 158 | labels: 159 | app: cert-manager 160 | rules: 161 | # Use to update challenge resource status 162 | - apiGroups: ["acme.cert-manager.io"] 163 | resources: ["challenges", "challenges/status"] 164 | verbs: ["update"] 165 | # Used to watch challenge resources 166 | - apiGroups: ["acme.cert-manager.io"] 167 | resources: ["challenges"] 168 | verbs: ["get", "list", "watch"] 169 | # Used to watch challenges, issuer and clusterissuer resources 170 | - apiGroups: ["cert-manager.io"] 171 | resources: ["issuers", "clusterissuers"] 172 | verbs: ["get", "list", "watch"] 173 | # Need to be able to retrieve ACME account private key to complete challenges 174 | - apiGroups: [""] 175 | resources: ["secrets"] 176 | verbs: ["get", "list", "watch"] 177 | # Used to create events 178 | - apiGroups: [""] 179 | resources: ["events"] 180 | verbs: ["create", "patch"] 181 | # HTTP01 rules 182 | - apiGroups: [""] 183 | resources: ["pods", "services"] 184 | verbs: ["get", "list", "watch", "create", "delete"] 185 | - apiGroups: ["extensions"] 186 | resources: ["ingresses"] 187 | verbs: ["get", "list", "watch", "create", "delete", "update"] 188 | # We require these rules to support users with the OwnerReferencesPermissionEnforcement 189 | # admission controller enabled: 190 | # https://kubernetes.io/docs/reference/access-authn-authz/admission-controllers/#ownerreferencespermissionenforcement 191 | - apiGroups: ["acme.cert-manager.io"] 192 | resources: ["challenges/finalizers"] 193 | verbs: ["update"] 194 | # DNS01 rules (duplicated above) 195 | - apiGroups: [""] 196 | resources: ["secrets"] 197 | verbs: ["get", "list", "watch"] 198 | 199 | --- 200 | 201 | # ingress-shim controller role 202 | apiVersion: rbac.authorization.k8s.io/v1beta1 203 | kind: ClusterRole 204 | metadata: 205 | name: cert-manager-controller-ingress-shim 206 | labels: 207 | app: cert-manager 208 | rules: 209 | - apiGroups: ["cert-manager.io"] 210 | resources: ["certificates", "certificaterequests"] 211 | verbs: ["create", "update", "delete"] 212 | - apiGroups: ["cert-manager.io"] 213 | resources: ["certificates", "certificaterequests", "issuers", "clusterissuers"] 214 | verbs: ["get", "list", "watch"] 215 | - apiGroups: ["extensions"] 216 | resources: ["ingresses"] 217 | verbs: ["get", "list", "watch"] 218 | # We require these rules to support users with the OwnerReferencesPermissionEnforcement 219 | # admission controller enabled: 220 | # https://kubernetes.io/docs/reference/access-authn-authz/admission-controllers/#ownerreferencespermissionenforcement 221 | - apiGroups: ["extensions"] 222 | resources: ["ingresses/finalizers"] 223 | verbs: ["update"] 224 | - apiGroups: [""] 225 | resources: ["events"] 226 | verbs: ["create", "patch"] 227 | 228 | --- 229 | 230 | apiVersion: rbac.authorization.k8s.io/v1beta1 231 | kind: ClusterRoleBinding 232 | metadata: 233 | name: cert-manager-controller-issuers 234 | labels: 235 | app: cert-manager 236 | roleRef: 237 | apiGroup: rbac.authorization.k8s.io 238 | kind: ClusterRole 239 | name: cert-manager-controller-issuers 240 | subjects: 241 | - name: cert-manager 242 | namespace: kubeplatform # "cert-manager" 243 | kind: ServiceAccount 244 | 245 | --- 246 | 247 | apiVersion: rbac.authorization.k8s.io/v1beta1 248 | kind: ClusterRoleBinding 249 | metadata: 250 | name: cert-manager-controller-clusterissuers 251 | labels: 252 | app: cert-manager 253 | roleRef: 254 | apiGroup: rbac.authorization.k8s.io 255 | kind: ClusterRole 256 | name: cert-manager-controller-clusterissuers 257 | subjects: 258 | - name: cert-manager 259 | namespace: kubeplatform # "cert-manager" 260 | kind: ServiceAccount 261 | 262 | --- 263 | 264 | apiVersion: rbac.authorization.k8s.io/v1beta1 265 | kind: ClusterRoleBinding 266 | metadata: 267 | name: cert-manager-controller-certificates 268 | labels: 269 | app: cert-manager 270 | roleRef: 271 | apiGroup: rbac.authorization.k8s.io 272 | kind: ClusterRole 273 | name: cert-manager-controller-certificates 274 | subjects: 275 | - name: cert-manager 276 | namespace: kubeplatform # "cert-manager" 277 | kind: ServiceAccount 278 | 279 | --- 280 | 281 | apiVersion: rbac.authorization.k8s.io/v1beta1 282 | kind: ClusterRoleBinding 283 | metadata: 284 | name: cert-manager-controller-orders 285 | labels: 286 | app: cert-manager 287 | roleRef: 288 | apiGroup: rbac.authorization.k8s.io 289 | kind: ClusterRole 290 | name: cert-manager-controller-orders 291 | subjects: 292 | - name: cert-manager 293 | namespace: kubeplatform # "cert-manager" 294 | kind: ServiceAccount 295 | 296 | --- 297 | 298 | apiVersion: rbac.authorization.k8s.io/v1beta1 299 | kind: ClusterRoleBinding 300 | metadata: 301 | name: cert-manager-controller-challenges 302 | labels: 303 | app: cert-manager 304 | roleRef: 305 | apiGroup: rbac.authorization.k8s.io 306 | kind: ClusterRole 307 | name: cert-manager-controller-challenges 308 | subjects: 309 | - name: cert-manager 310 | namespace: kubeplatform # "cert-manager" 311 | kind: ServiceAccount 312 | 313 | --- 314 | 315 | apiVersion: rbac.authorization.k8s.io/v1beta1 316 | kind: ClusterRoleBinding 317 | metadata: 318 | name: cert-manager-controller-ingress-shim 319 | labels: 320 | app: cert-manager 321 | roleRef: 322 | apiGroup: rbac.authorization.k8s.io 323 | kind: ClusterRole 324 | name: cert-manager-controller-ingress-shim 325 | subjects: 326 | - name: cert-manager 327 | namespace: kubeplatform # "cert-manager" 328 | kind: ServiceAccount 329 | 330 | --- 331 | 332 | apiVersion: rbac.authorization.k8s.io/v1 333 | kind: ClusterRole 334 | metadata: 335 | name: cert-manager-view 336 | labels: 337 | app: cert-manager 338 | rbac.authorization.k8s.io/aggregate-to-view: "true" 339 | rbac.authorization.k8s.io/aggregate-to-edit: "true" 340 | rbac.authorization.k8s.io/aggregate-to-admin: "true" 341 | rules: 342 | - apiGroups: ["cert-manager.io"] 343 | resources: ["certificates", "certificaterequests", "issuers"] 344 | verbs: ["get", "list", "watch"] 345 | 346 | --- 347 | 348 | apiVersion: rbac.authorization.k8s.io/v1 349 | kind: ClusterRole 350 | metadata: 351 | name: cert-manager-edit 352 | labels: 353 | app: cert-manager 354 | rbac.authorization.k8s.io/aggregate-to-edit: "true" 355 | rbac.authorization.k8s.io/aggregate-to-admin: "true" 356 | rules: 357 | - apiGroups: ["cert-manager.io"] 358 | resources: ["certificates", "certificaterequests", "issuers"] 359 | verbs: ["create", "delete", "deletecollection", "patch", "update"] 360 | -------------------------------------------------------------------------------- /cert-manager/sa.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ServiceAccount 3 | metadata: 4 | name: cert-manager 5 | -------------------------------------------------------------------------------- /external-dns/deployment.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: external-dns 5 | spec: 6 | replicas: 1 7 | selector: 8 | matchLabels: 9 | name: external-dns 10 | template: 11 | metadata: 12 | annotations: 13 | prometheus.io/path: /metrics 14 | prometheus.io/port: "7979" 15 | prometheus.io/scrape: "true" 16 | labels: 17 | name: external-dns 18 | spec: 19 | containers: 20 | - name: external-dns 21 | env: 22 | - name: GOOGLE_APPLICATION_CREDENTIALS 23 | value: /google/credentials.json 24 | image: bitnami/external-dns:0.7.3 25 | livenessProbe: 26 | httpGet: 27 | path: /healthz 28 | port: metrics 29 | scheme: HTTP 30 | ports: 31 | - containerPort: 7979 32 | name: metrics 33 | protocol: TCP 34 | readinessProbe: 35 | httpGet: 36 | path: /healthz 37 | port: metrics 38 | scheme: HTTP 39 | volumeMounts: 40 | - mountPath: /google 41 | name: gcreds 42 | readOnly: true 43 | serviceAccountName: external-dns 44 | volumes: 45 | - name: gcreds 46 | secret: 47 | defaultMode: 420 48 | secretName: external-dns-credentials -------------------------------------------------------------------------------- /external-dns/rbac.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1beta1 2 | kind: ClusterRole 3 | metadata: 4 | name: external-dns 5 | rules: 6 | - apiGroups: [""] 7 | resources: ["services","endpoints","pods"] 8 | verbs: ["get","watch","list"] 9 | - apiGroups: ["extensions","networking.k8s.io"] 10 | resources: ["ingresses"] 11 | verbs: ["get","watch","list"] 12 | - apiGroups: [""] 13 | resources: ["nodes"] 14 | verbs: ["list"] 15 | 16 | --- 17 | apiVersion: rbac.authorization.k8s.io/v1beta1 18 | kind: ClusterRoleBinding 19 | metadata: 20 | name: external-dns-viewer 21 | roleRef: 22 | apiGroup: rbac.authorization.k8s.io 23 | kind: ClusterRole 24 | name: external-dns 25 | subjects: 26 | - kind: ServiceAccount 27 | name: external-dns 28 | namespace: kubeplatform 29 | -------------------------------------------------------------------------------- /external-dns/sa.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ServiceAccount 3 | metadata: 4 | name: external-dns 5 | -------------------------------------------------------------------------------- /keycloak/cm.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ConfigMap 3 | metadata: 4 | labels: 5 | app: keycloak 6 | name: keycloak 7 | data: 8 | keycloak.cli: | 9 | embed-server --std-out=echo 10 | batch 11 | 12 | # Makes node identifier unique getting rid of a warning in the logs 13 | /subsystem=transactions:write-attribute(name=node-identifier, value=${jboss.node.name}) 14 | 15 | 16 | # Allow log level to be configured via environment variable 17 | /subsystem=logging/console-handler=CONSOLE:write-attribute(name=level, value=${env.WILDFLY_LOGLEVEL:INFO}) 18 | /subsystem=logging/root-logger=ROOT:write-attribute(name=level, value=${env.WILDFLY_LOGLEVEL:INFO}) 19 | 20 | # Log only to console 21 | /subsystem=logging/root-logger=ROOT:write-attribute(name=handlers, value=[CONSOLE]) 22 | 23 | 24 | /socket-binding-group=standard-sockets/socket-binding=proxy-https:add(port=443) 25 | /subsystem=undertow/server=default-server/http-listener=default:write-attribute(name=redirect-socket, value=proxy-https) 26 | /subsystem=undertow/server=default-server/http-listener=default:write-attribute(name=proxy-address-forwarding, value=true) 27 | 28 | 29 | run-batch 30 | stop-embedded-server 31 | keycloak.sh: | 32 | #!/usr/bin/env bash 33 | 34 | set -eu 35 | 36 | /opt/jboss/keycloak/bin/jboss-cli.sh --file=/scripts/keycloak.cli 37 | 38 | exec /opt/jboss/tools/docker-entrypoint.sh -b 0.0.0.0 -c standalone.xml 39 | exit "$?" 40 | -------------------------------------------------------------------------------- /keycloak/ingress.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: networking.k8s.io/v1beta1 2 | kind: Ingress 3 | metadata: 4 | annotations: 5 | kubernetes.io/ingress.class: nginx 6 | kubernetes.io/tls-acme: "true" 7 | nginx.ingress.kubernetes.io/enable-cors: "true" 8 | # Wildcards are ignored by some browsers. That's why kbn-version for Kibana is added here 9 | nginx.ingress.kubernetes.io/cors-allow-headers: "kbn-version,DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization" 10 | name: keycloak 11 | spec: 12 | rules: 13 | - host: keycloak.$(PLATFORM_CONFIG_DOMAIN) 14 | http: 15 | paths: 16 | - backend: 17 | serviceName: keycloak-http 18 | servicePort: 80 19 | path: / 20 | tls: 21 | - hosts: 22 | - keycloak.$(PLATFORM_CONFIG_DOMAIN) 23 | secretName: keycloak-tls 24 | -------------------------------------------------------------------------------- /keycloak/kustomization.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kustomize.config.k8s.io/v1beta1 2 | kind: Kustomization 3 | 4 | resources: 5 | - cm.yaml 6 | - ingress.yaml 7 | - services.yaml 8 | - statefulset.yaml 9 | 10 | configMapGenerator: 11 | - name: realm-export 12 | files: 13 | - realm-export.json 14 | 15 | vars: 16 | - name: POSTGRESQL 17 | objref: 18 | kind: Service 19 | name: postgresql 20 | apiVersion: v1 -------------------------------------------------------------------------------- /keycloak/realm-export.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "KubePlatform", 3 | "realm": "KubePlatform", 4 | "notBefore": 0, 5 | "revokeRefreshToken": false, 6 | "refreshTokenMaxReuse": 0, 7 | "accessTokenLifespan": 300, 8 | "accessTokenLifespanForImplicitFlow": 900, 9 | "ssoSessionIdleTimeout": 1800, 10 | "ssoSessionMaxLifespan": 36000, 11 | "offlineSessionIdleTimeout": 2592000, 12 | "offlineSessionMaxLifespanEnabled": false, 13 | "offlineSessionMaxLifespan": 5184000, 14 | "accessCodeLifespan": 60, 15 | "accessCodeLifespanUserAction": 300, 16 | "accessCodeLifespanLogin": 1800, 17 | "actionTokenGeneratedByAdminLifespan": 43200, 18 | "actionTokenGeneratedByUserLifespan": 300, 19 | "enabled": true, 20 | "sslRequired": "external", 21 | "registrationAllowed": false, 22 | "registrationEmailAsUsername": false, 23 | "rememberMe": false, 24 | "verifyEmail": false, 25 | "loginWithEmailAllowed": true, 26 | "duplicateEmailsAllowed": false, 27 | "resetPasswordAllowed": false, 28 | "editUsernameAllowed": false, 29 | "bruteForceProtected": false, 30 | "permanentLockout": false, 31 | "maxFailureWaitSeconds": 900, 32 | "minimumQuickLoginWaitSeconds": 60, 33 | "waitIncrementSeconds": 60, 34 | "quickLoginCheckMilliSeconds": 1000, 35 | "maxDeltaTimeSeconds": 43200, 36 | "failureFactor": 30, 37 | "defaultRoles": [ 38 | "uma_authorization", 39 | "offline_access" 40 | ], 41 | "requiredCredentials": [ 42 | "password" 43 | ], 44 | "otpPolicyType": "totp", 45 | "otpPolicyAlgorithm": "HmacSHA1", 46 | "otpPolicyInitialCounter": 0, 47 | "otpPolicyDigits": 6, 48 | "otpPolicyLookAheadWindow": 1, 49 | "otpPolicyPeriod": 30, 50 | "otpSupportedApplications": [ 51 | "FreeOTP", 52 | "Google Authenticator" 53 | ], 54 | "scopeMappings": [ 55 | { 56 | "clientScope": "offline_access", 57 | "roles": [ 58 | "offline_access" 59 | ] 60 | } 61 | ], 62 | "clients": [ 63 | { 64 | "id": "cdc602fe-47c7-45c7-a17d-45fd512946c4", 65 | "clientId": "kubeplatform", 66 | "surrogateAuthRequired": false, 67 | "enabled": true, 68 | "clientAuthenticatorType": "client-secret", 69 | "secret": "08ee025d-6b66-4e7a-8a4a-0f1cc9e8b2a2", 70 | "redirectUris": [ 71 | "*" 72 | ], 73 | "webOrigins": [], 74 | "notBefore": 0, 75 | "bearerOnly": false, 76 | "consentRequired": false, 77 | "standardFlowEnabled": true, 78 | "implicitFlowEnabled": false, 79 | "directAccessGrantsEnabled": false, 80 | "serviceAccountsEnabled": false, 81 | "publicClient": false, 82 | "frontchannelLogout": false, 83 | "protocol": "openid-connect", 84 | "attributes": { 85 | "saml.assertion.signature": "false", 86 | "saml.force.post.binding": "false", 87 | "saml.multivalued.roles": "false", 88 | "saml.encrypt": "false", 89 | "saml.server.signature": "false", 90 | "saml.server.signature.keyinfo.ext": "false", 91 | "exclude.session.state.from.auth.response": "false", 92 | "saml_force_name_id_format": "false", 93 | "saml.client.signature": "false", 94 | "tls.client.certificate.bound.access.tokens": "false", 95 | "saml.authnstatement": "false", 96 | "display.on.consent.screen": "false", 97 | "saml.onetimeuse.condition": "false" 98 | }, 99 | "authenticationFlowBindingOverrides": {}, 100 | "fullScopeAllowed": true, 101 | "nodeReRegistrationTimeout": -1, 102 | "defaultClientScopes": [ 103 | "role_list", 104 | "profile", 105 | "email" 106 | ], 107 | "optionalClientScopes": [ 108 | "address", 109 | "phone", 110 | "offline_access" 111 | ] 112 | }, 113 | { 114 | "id": "60b94664-d689-4d4a-a62f-c891dcf5bd87", 115 | "clientId": "broker", 116 | "name": "${client_broker}", 117 | "surrogateAuthRequired": false, 118 | "enabled": true, 119 | "clientAuthenticatorType": "client-secret", 120 | "secret": "**********", 121 | "redirectUris": [], 122 | "webOrigins": [], 123 | "notBefore": 0, 124 | "bearerOnly": false, 125 | "consentRequired": false, 126 | "standardFlowEnabled": true, 127 | "implicitFlowEnabled": false, 128 | "directAccessGrantsEnabled": false, 129 | "serviceAccountsEnabled": false, 130 | "publicClient": false, 131 | "frontchannelLogout": false, 132 | "protocol": "openid-connect", 133 | "attributes": {}, 134 | "authenticationFlowBindingOverrides": {}, 135 | "fullScopeAllowed": false, 136 | "nodeReRegistrationTimeout": 0, 137 | "defaultClientScopes": [ 138 | "role_list", 139 | "profile", 140 | "email" 141 | ], 142 | "optionalClientScopes": [ 143 | "address", 144 | "phone", 145 | "offline_access" 146 | ] 147 | }, 148 | { 149 | "id": "f353a0aa-4909-4951-a2da-301599d25d0a", 150 | "clientId": "admin-cli", 151 | "name": "${client_admin-cli}", 152 | "surrogateAuthRequired": false, 153 | "enabled": true, 154 | "clientAuthenticatorType": "client-secret", 155 | "secret": "**********", 156 | "redirectUris": [], 157 | "webOrigins": [], 158 | "notBefore": 0, 159 | "bearerOnly": false, 160 | "consentRequired": false, 161 | "standardFlowEnabled": false, 162 | "implicitFlowEnabled": false, 163 | "directAccessGrantsEnabled": true, 164 | "serviceAccountsEnabled": false, 165 | "publicClient": true, 166 | "frontchannelLogout": false, 167 | "protocol": "openid-connect", 168 | "attributes": {}, 169 | "authenticationFlowBindingOverrides": {}, 170 | "fullScopeAllowed": false, 171 | "nodeReRegistrationTimeout": 0, 172 | "defaultClientScopes": [ 173 | "role_list", 174 | "profile", 175 | "email" 176 | ], 177 | "optionalClientScopes": [ 178 | "address", 179 | "phone", 180 | "offline_access" 181 | ] 182 | }, 183 | { 184 | "id": "82a99d77-f901-43b4-86ad-379ea18c4687", 185 | "clientId": "security-admin-console", 186 | "name": "${client_security-admin-console}", 187 | "baseUrl": "/auth/admin/KubePlatform/console/index.html", 188 | "surrogateAuthRequired": false, 189 | "enabled": true, 190 | "clientAuthenticatorType": "client-secret", 191 | "secret": "**********", 192 | "redirectUris": [ 193 | "/auth/admin/KubePlatform/console/*" 194 | ], 195 | "webOrigins": [], 196 | "notBefore": 0, 197 | "bearerOnly": false, 198 | "consentRequired": false, 199 | "standardFlowEnabled": true, 200 | "implicitFlowEnabled": false, 201 | "directAccessGrantsEnabled": false, 202 | "serviceAccountsEnabled": false, 203 | "publicClient": true, 204 | "frontchannelLogout": false, 205 | "protocol": "openid-connect", 206 | "attributes": {}, 207 | "authenticationFlowBindingOverrides": {}, 208 | "fullScopeAllowed": false, 209 | "nodeReRegistrationTimeout": 0, 210 | "protocolMappers": [ 211 | { 212 | "id": "028926ea-7012-484e-8acd-33604fe1087b", 213 | "name": "locale", 214 | "protocol": "openid-connect", 215 | "protocolMapper": "oidc-usermodel-attribute-mapper", 216 | "consentRequired": false, 217 | "config": { 218 | "userinfo.token.claim": "true", 219 | "user.attribute": "locale", 220 | "id.token.claim": "true", 221 | "access.token.claim": "true", 222 | "claim.name": "locale", 223 | "jsonType.label": "String" 224 | } 225 | } 226 | ], 227 | "defaultClientScopes": [ 228 | "role_list", 229 | "profile", 230 | "email" 231 | ], 232 | "optionalClientScopes": [ 233 | "address", 234 | "phone", 235 | "offline_access" 236 | ] 237 | }, 238 | { 239 | "id": "686ff4e6-a0f7-45bf-9d7c-a22c0b6b84a6", 240 | "clientId": "account", 241 | "name": "${client_account}", 242 | "baseUrl": "/auth/realms/KubePlatform/account", 243 | "surrogateAuthRequired": false, 244 | "enabled": true, 245 | "clientAuthenticatorType": "client-secret", 246 | "secret": "**********", 247 | "defaultRoles": [ 248 | "manage-account", 249 | "view-profile" 250 | ], 251 | "redirectUris": [ 252 | "/auth/realms/KubePlatform/account/*" 253 | ], 254 | "webOrigins": [], 255 | "notBefore": 0, 256 | "bearerOnly": false, 257 | "consentRequired": false, 258 | "standardFlowEnabled": true, 259 | "implicitFlowEnabled": false, 260 | "directAccessGrantsEnabled": false, 261 | "serviceAccountsEnabled": false, 262 | "publicClient": false, 263 | "frontchannelLogout": false, 264 | "protocol": "openid-connect", 265 | "attributes": {}, 266 | "authenticationFlowBindingOverrides": {}, 267 | "fullScopeAllowed": false, 268 | "nodeReRegistrationTimeout": 0, 269 | "defaultClientScopes": [ 270 | "role_list", 271 | "profile", 272 | "email" 273 | ], 274 | "optionalClientScopes": [ 275 | "address", 276 | "phone", 277 | "offline_access" 278 | ] 279 | }, 280 | { 281 | "id": "10bbc901-2c34-4016-ba8e-e6a35c1bde91", 282 | "clientId": "realm-management", 283 | "name": "${client_realm-management}", 284 | "surrogateAuthRequired": false, 285 | "enabled": true, 286 | "clientAuthenticatorType": "client-secret", 287 | "secret": "**********", 288 | "redirectUris": [], 289 | "webOrigins": [], 290 | "notBefore": 0, 291 | "bearerOnly": true, 292 | "consentRequired": false, 293 | "standardFlowEnabled": true, 294 | "implicitFlowEnabled": false, 295 | "directAccessGrantsEnabled": false, 296 | "serviceAccountsEnabled": false, 297 | "publicClient": false, 298 | "frontchannelLogout": false, 299 | "protocol": "openid-connect", 300 | "attributes": {}, 301 | "authenticationFlowBindingOverrides": {}, 302 | "fullScopeAllowed": false, 303 | "nodeReRegistrationTimeout": 0, 304 | "defaultClientScopes": [ 305 | "role_list", 306 | "profile", 307 | "email" 308 | ], 309 | "optionalClientScopes": [ 310 | "address", 311 | "phone", 312 | "offline_access" 313 | ] 314 | } 315 | ], 316 | "clientScopes": [ 317 | { 318 | "id": "78e8a213-7f2f-4ea3-a6c8-49172f54cda3", 319 | "name": "address", 320 | "description": "OpenID Connect built-in scope: address", 321 | "protocol": "openid-connect", 322 | "attributes": { 323 | "consent.screen.text": "${addressScopeConsentText}", 324 | "display.on.consent.screen": "true" 325 | }, 326 | "protocolMappers": [ 327 | { 328 | "id": "ff953225-8799-4597-bb89-ea9da0f39aed", 329 | "name": "address", 330 | "protocol": "openid-connect", 331 | "protocolMapper": "oidc-address-mapper", 332 | "consentRequired": false, 333 | "config": { 334 | "user.attribute.formatted": "formatted", 335 | "user.attribute.country": "country", 336 | "user.attribute.postal_code": "postal_code", 337 | "userinfo.token.claim": "true", 338 | "user.attribute.street": "street", 339 | "id.token.claim": "true", 340 | "user.attribute.region": "region", 341 | "access.token.claim": "true", 342 | "user.attribute.locality": "locality" 343 | } 344 | } 345 | ] 346 | }, 347 | { 348 | "id": "be13df0e-9a4d-459b-84a6-7051853c562e", 349 | "name": "email", 350 | "description": "OpenID Connect built-in scope: email", 351 | "protocol": "openid-connect", 352 | "attributes": { 353 | "consent.screen.text": "${emailScopeConsentText}", 354 | "display.on.consent.screen": "true" 355 | }, 356 | "protocolMappers": [ 357 | { 358 | "id": "cb43f02a-1335-4909-bd0a-91abaf96f864", 359 | "name": "email", 360 | "protocol": "openid-connect", 361 | "protocolMapper": "oidc-usermodel-property-mapper", 362 | "consentRequired": false, 363 | "config": { 364 | "userinfo.token.claim": "true", 365 | "user.attribute": "email", 366 | "id.token.claim": "true", 367 | "access.token.claim": "true", 368 | "claim.name": "email", 369 | "jsonType.label": "String" 370 | } 371 | }, 372 | { 373 | "id": "9fca6f5a-fef5-4b62-92bd-32bcda33d0b9", 374 | "name": "email verified", 375 | "protocol": "openid-connect", 376 | "protocolMapper": "oidc-usermodel-property-mapper", 377 | "consentRequired": false, 378 | "config": { 379 | "userinfo.token.claim": "true", 380 | "user.attribute": "emailVerified", 381 | "id.token.claim": "true", 382 | "access.token.claim": "true", 383 | "claim.name": "email_verified", 384 | "jsonType.label": "boolean" 385 | } 386 | } 387 | ] 388 | }, 389 | { 390 | "id": "0e6baee6-eb87-4628-97a9-a4260005b475", 391 | "name": "offline_access", 392 | "description": "OpenID Connect built-in scope: offline_access", 393 | "protocol": "openid-connect", 394 | "attributes": { 395 | "consent.screen.text": "${offlineAccessScopeConsentText}", 396 | "display.on.consent.screen": "true" 397 | } 398 | }, 399 | { 400 | "id": "bbb334b2-d673-4f3e-92fd-c5531bbc1fbf", 401 | "name": "phone", 402 | "description": "OpenID Connect built-in scope: phone", 403 | "protocol": "openid-connect", 404 | "attributes": { 405 | "consent.screen.text": "${phoneScopeConsentText}", 406 | "display.on.consent.screen": "true" 407 | }, 408 | "protocolMappers": [ 409 | { 410 | "id": "e49eaed4-dbf3-4d85-971c-5a4a14df0420", 411 | "name": "phone number verified", 412 | "protocol": "openid-connect", 413 | "protocolMapper": "oidc-usermodel-attribute-mapper", 414 | "consentRequired": false, 415 | "config": { 416 | "userinfo.token.claim": "true", 417 | "user.attribute": "phoneNumberVerified", 418 | "id.token.claim": "true", 419 | "access.token.claim": "true", 420 | "claim.name": "phone_number_verified", 421 | "jsonType.label": "boolean" 422 | } 423 | }, 424 | { 425 | "id": "fbd526a2-fa8c-4907-8a77-5b772a9f243f", 426 | "name": "phone number", 427 | "protocol": "openid-connect", 428 | "protocolMapper": "oidc-usermodel-attribute-mapper", 429 | "consentRequired": false, 430 | "config": { 431 | "userinfo.token.claim": "true", 432 | "user.attribute": "phoneNumber", 433 | "id.token.claim": "true", 434 | "access.token.claim": "true", 435 | "claim.name": "phone_number", 436 | "jsonType.label": "String" 437 | } 438 | } 439 | ] 440 | }, 441 | { 442 | "id": "e2b59576-ab59-45ea-b470-04666102a837", 443 | "name": "profile", 444 | "description": "OpenID Connect built-in scope: profile", 445 | "protocol": "openid-connect", 446 | "attributes": { 447 | "consent.screen.text": "${profileScopeConsentText}", 448 | "display.on.consent.screen": "true" 449 | }, 450 | "protocolMappers": [ 451 | { 452 | "id": "fa25a9c3-80c2-4868-ad66-66275858aae1", 453 | "name": "picture", 454 | "protocol": "openid-connect", 455 | "protocolMapper": "oidc-usermodel-attribute-mapper", 456 | "consentRequired": false, 457 | "config": { 458 | "userinfo.token.claim": "true", 459 | "user.attribute": "picture", 460 | "id.token.claim": "true", 461 | "access.token.claim": "true", 462 | "claim.name": "picture", 463 | "jsonType.label": "String" 464 | } 465 | }, 466 | { 467 | "id": "95a4136d-0eaf-45c4-a6a3-7e2563d1289a", 468 | "name": "profile", 469 | "protocol": "openid-connect", 470 | "protocolMapper": "oidc-usermodel-attribute-mapper", 471 | "consentRequired": false, 472 | "config": { 473 | "userinfo.token.claim": "true", 474 | "user.attribute": "profile", 475 | "id.token.claim": "true", 476 | "access.token.claim": "true", 477 | "claim.name": "profile", 478 | "jsonType.label": "String" 479 | } 480 | }, 481 | { 482 | "id": "3c4c34c6-d90c-4285-ade3-ed7fa2fe3fa1", 483 | "name": "given name", 484 | "protocol": "openid-connect", 485 | "protocolMapper": "oidc-usermodel-property-mapper", 486 | "consentRequired": false, 487 | "config": { 488 | "userinfo.token.claim": "true", 489 | "user.attribute": "firstName", 490 | "id.token.claim": "true", 491 | "access.token.claim": "true", 492 | "claim.name": "given_name", 493 | "jsonType.label": "String" 494 | } 495 | }, 496 | { 497 | "id": "4b092668-1597-443a-9d7c-2ddcb09637ab", 498 | "name": "middle name", 499 | "protocol": "openid-connect", 500 | "protocolMapper": "oidc-usermodel-attribute-mapper", 501 | "consentRequired": false, 502 | "config": { 503 | "userinfo.token.claim": "true", 504 | "user.attribute": "middleName", 505 | "id.token.claim": "true", 506 | "access.token.claim": "true", 507 | "claim.name": "middle_name", 508 | "jsonType.label": "String" 509 | } 510 | }, 511 | { 512 | "id": "e9d0028f-bdce-49a4-b3ea-fd22d5f64a62", 513 | "name": "gender", 514 | "protocol": "openid-connect", 515 | "protocolMapper": "oidc-usermodel-attribute-mapper", 516 | "consentRequired": false, 517 | "config": { 518 | "userinfo.token.claim": "true", 519 | "user.attribute": "gender", 520 | "id.token.claim": "true", 521 | "access.token.claim": "true", 522 | "claim.name": "gender", 523 | "jsonType.label": "String" 524 | } 525 | }, 526 | { 527 | "id": "99b4a6ab-6364-47e5-8453-f31660a27314", 528 | "name": "family name", 529 | "protocol": "openid-connect", 530 | "protocolMapper": "oidc-usermodel-property-mapper", 531 | "consentRequired": false, 532 | "config": { 533 | "userinfo.token.claim": "true", 534 | "user.attribute": "lastName", 535 | "id.token.claim": "true", 536 | "access.token.claim": "true", 537 | "claim.name": "family_name", 538 | "jsonType.label": "String" 539 | } 540 | }, 541 | { 542 | "id": "594a679e-8725-4e12-98d6-08240f8b20c6", 543 | "name": "username", 544 | "protocol": "openid-connect", 545 | "protocolMapper": "oidc-usermodel-property-mapper", 546 | "consentRequired": false, 547 | "config": { 548 | "userinfo.token.claim": "true", 549 | "user.attribute": "username", 550 | "id.token.claim": "true", 551 | "access.token.claim": "true", 552 | "claim.name": "preferred_username", 553 | "jsonType.label": "String" 554 | } 555 | }, 556 | { 557 | "id": "18dc4513-1f3d-4cdd-953d-9682ea3bafdb", 558 | "name": "birthdate", 559 | "protocol": "openid-connect", 560 | "protocolMapper": "oidc-usermodel-attribute-mapper", 561 | "consentRequired": false, 562 | "config": { 563 | "userinfo.token.claim": "true", 564 | "user.attribute": "birthdate", 565 | "id.token.claim": "true", 566 | "access.token.claim": "true", 567 | "claim.name": "birthdate", 568 | "jsonType.label": "String" 569 | } 570 | }, 571 | { 572 | "id": "426f6197-5855-4586-ad88-c703598b3314", 573 | "name": "updated at", 574 | "protocol": "openid-connect", 575 | "protocolMapper": "oidc-usermodel-attribute-mapper", 576 | "consentRequired": false, 577 | "config": { 578 | "userinfo.token.claim": "true", 579 | "user.attribute": "updatedAt", 580 | "id.token.claim": "true", 581 | "access.token.claim": "true", 582 | "claim.name": "updated_at", 583 | "jsonType.label": "String" 584 | } 585 | }, 586 | { 587 | "id": "8c8a5e40-eb79-4f12-af25-d504416a7ad1", 588 | "name": "nickname", 589 | "protocol": "openid-connect", 590 | "protocolMapper": "oidc-usermodel-attribute-mapper", 591 | "consentRequired": false, 592 | "config": { 593 | "userinfo.token.claim": "true", 594 | "user.attribute": "nickname", 595 | "id.token.claim": "true", 596 | "access.token.claim": "true", 597 | "claim.name": "nickname", 598 | "jsonType.label": "String" 599 | } 600 | }, 601 | { 602 | "id": "e444ccd2-5afd-4a4e-814e-7236bbbf400a", 603 | "name": "zoneinfo", 604 | "protocol": "openid-connect", 605 | "protocolMapper": "oidc-usermodel-attribute-mapper", 606 | "consentRequired": false, 607 | "config": { 608 | "userinfo.token.claim": "true", 609 | "user.attribute": "zoneinfo", 610 | "id.token.claim": "true", 611 | "access.token.claim": "true", 612 | "claim.name": "zoneinfo", 613 | "jsonType.label": "String" 614 | } 615 | }, 616 | { 617 | "id": "1759310d-1003-4111-9fd2-c09fa49a1439", 618 | "name": "website", 619 | "protocol": "openid-connect", 620 | "protocolMapper": "oidc-usermodel-attribute-mapper", 621 | "consentRequired": false, 622 | "config": { 623 | "userinfo.token.claim": "true", 624 | "user.attribute": "website", 625 | "id.token.claim": "true", 626 | "access.token.claim": "true", 627 | "claim.name": "website", 628 | "jsonType.label": "String" 629 | } 630 | }, 631 | { 632 | "id": "23b9b9aa-1ab3-4901-9959-af5b1c86f5ed", 633 | "name": "full name", 634 | "protocol": "openid-connect", 635 | "protocolMapper": "oidc-full-name-mapper", 636 | "consentRequired": false, 637 | "config": { 638 | "id.token.claim": "true", 639 | "access.token.claim": "true", 640 | "userinfo.token.claim": "true" 641 | } 642 | }, 643 | { 644 | "id": "44f7402f-bb68-4953-9ed7-53ec07d8ada8", 645 | "name": "locale", 646 | "protocol": "openid-connect", 647 | "protocolMapper": "oidc-usermodel-attribute-mapper", 648 | "consentRequired": false, 649 | "config": { 650 | "userinfo.token.claim": "true", 651 | "user.attribute": "locale", 652 | "id.token.claim": "true", 653 | "access.token.claim": "true", 654 | "claim.name": "locale", 655 | "jsonType.label": "String" 656 | } 657 | } 658 | ] 659 | }, 660 | { 661 | "id": "cb237f91-2d49-46a6-9bc0-33256d725f31", 662 | "name": "role_list", 663 | "description": "SAML role list", 664 | "protocol": "saml", 665 | "attributes": { 666 | "consent.screen.text": "${samlRoleListScopeConsentText}", 667 | "display.on.consent.screen": "true" 668 | }, 669 | "protocolMappers": [ 670 | { 671 | "id": "eab4e7bb-1de7-4a84-bd9d-72257d5b1477", 672 | "name": "role list", 673 | "protocol": "saml", 674 | "protocolMapper": "saml-role-list-mapper", 675 | "consentRequired": false, 676 | "config": { 677 | "single": "false", 678 | "attribute.nameformat": "Basic", 679 | "attribute.name": "Role" 680 | } 681 | } 682 | ] 683 | } 684 | ], 685 | "defaultDefaultClientScopes": [ 686 | "email", 687 | "role_list", 688 | "profile" 689 | ], 690 | "defaultOptionalClientScopes": [ 691 | "offline_access", 692 | "address", 693 | "phone" 694 | ], 695 | "browserSecurityHeaders": { 696 | "contentSecurityPolicyReportOnly": "", 697 | "xContentTypeOptions": "nosniff", 698 | "xRobotsTag": "none", 699 | "xFrameOptions": "SAMEORIGIN", 700 | "xXSSProtection": "1; mode=block", 701 | "contentSecurityPolicy": "frame-src 'self'; frame-ancestors 'self'; object-src 'none';", 702 | "strictTransportSecurity": "max-age=31536000; includeSubDomains" 703 | }, 704 | "smtpServer": {}, 705 | "eventsEnabled": false, 706 | "eventsListeners": [ 707 | "jboss-logging" 708 | ], 709 | "enabledEventTypes": [], 710 | "adminEventsEnabled": false, 711 | "adminEventsDetailsEnabled": false, 712 | "components": { 713 | "org.keycloak.services.clientregistration.policy.ClientRegistrationPolicy": [ 714 | { 715 | "id": "6252c932-478f-4f8f-b2ca-d742016a84aa", 716 | "name": "Allowed Protocol Mapper Types", 717 | "providerId": "allowed-protocol-mappers", 718 | "subType": "anonymous", 719 | "subComponents": {}, 720 | "config": { 721 | "allowed-protocol-mapper-types": [ 722 | "oidc-address-mapper", 723 | "saml-role-list-mapper", 724 | "oidc-full-name-mapper", 725 | "oidc-usermodel-attribute-mapper", 726 | "saml-user-property-mapper", 727 | "oidc-sha256-pairwise-sub-mapper", 728 | "oidc-usermodel-property-mapper", 729 | "saml-user-attribute-mapper" 730 | ] 731 | } 732 | }, 733 | { 734 | "id": "1fbfc4f3-073e-4fb8-a998-639aba3918e4", 735 | "name": "Max Clients Limit", 736 | "providerId": "max-clients", 737 | "subType": "anonymous", 738 | "subComponents": {}, 739 | "config": { 740 | "max-clients": [ 741 | "200" 742 | ] 743 | } 744 | }, 745 | { 746 | "id": "ef563844-0784-45fe-bcbd-75ba1f0ab8ee", 747 | "name": "Trusted Hosts", 748 | "providerId": "trusted-hosts", 749 | "subType": "anonymous", 750 | "subComponents": {}, 751 | "config": { 752 | "host-sending-registration-request-must-match": [ 753 | "true" 754 | ], 755 | "client-uris-must-match": [ 756 | "true" 757 | ] 758 | } 759 | }, 760 | { 761 | "id": "d7820d55-c469-4559-8a46-d04401e6c36b", 762 | "name": "Full Scope Disabled", 763 | "providerId": "scope", 764 | "subType": "anonymous", 765 | "subComponents": {}, 766 | "config": {} 767 | }, 768 | { 769 | "id": "bfbc3b13-2de0-4edf-a76d-ebe5145977cb", 770 | "name": "Allowed Client Scopes", 771 | "providerId": "allowed-client-templates", 772 | "subType": "anonymous", 773 | "subComponents": {}, 774 | "config": { 775 | "allow-default-scopes": [ 776 | "true" 777 | ] 778 | } 779 | }, 780 | { 781 | "id": "2b09a896-0e0b-4b62-9fd6-793a60cc9572", 782 | "name": "Allowed Protocol Mapper Types", 783 | "providerId": "allowed-protocol-mappers", 784 | "subType": "authenticated", 785 | "subComponents": {}, 786 | "config": { 787 | "allowed-protocol-mapper-types": [ 788 | "oidc-usermodel-attribute-mapper", 789 | "saml-user-attribute-mapper", 790 | "saml-user-property-mapper", 791 | "saml-role-list-mapper", 792 | "oidc-full-name-mapper", 793 | "oidc-usermodel-property-mapper", 794 | "oidc-address-mapper", 795 | "oidc-sha256-pairwise-sub-mapper" 796 | ] 797 | } 798 | }, 799 | { 800 | "id": "b2f5442e-a8f1-4e16-879c-5de7800742a6", 801 | "name": "Consent Required", 802 | "providerId": "consent-required", 803 | "subType": "anonymous", 804 | "subComponents": {}, 805 | "config": {} 806 | }, 807 | { 808 | "id": "bfbc3987-87de-42a0-8bf3-2ba07390a060", 809 | "name": "Allowed Client Scopes", 810 | "providerId": "allowed-client-templates", 811 | "subType": "authenticated", 812 | "subComponents": {}, 813 | "config": { 814 | "allow-default-scopes": [ 815 | "true" 816 | ] 817 | } 818 | } 819 | ], 820 | "org.keycloak.keys.KeyProvider": [ 821 | { 822 | "id": "bedb5287-01da-44ab-b95e-2f7d17de5c28", 823 | "name": "rsa-generated", 824 | "providerId": "rsa-generated", 825 | "subComponents": {}, 826 | "config": { 827 | "priority": [ 828 | "100" 829 | ] 830 | } 831 | }, 832 | { 833 | "id": "c0f7dbc6-eb75-482c-944d-a67608a50f97", 834 | "name": "aes-generated", 835 | "providerId": "aes-generated", 836 | "subComponents": {}, 837 | "config": { 838 | "priority": [ 839 | "100" 840 | ] 841 | } 842 | }, 843 | { 844 | "id": "2bc2e0f0-1770-4cb8-a4b1-36a4e01aaf82", 845 | "name": "hmac-generated", 846 | "providerId": "hmac-generated", 847 | "subComponents": {}, 848 | "config": { 849 | "priority": [ 850 | "100" 851 | ], 852 | "algorithm": [ 853 | "HS256" 854 | ] 855 | } 856 | } 857 | ] 858 | }, 859 | "internationalizationEnabled": false, 860 | "supportedLocales": [], 861 | "authenticationFlows": [ 862 | { 863 | "id": "c381f664-ee9c-4f6f-84aa-eb67d9e85779", 864 | "alias": "Handle Existing Account", 865 | "description": "Handle what to do if there is existing account with same email/username like authenticated identity provider", 866 | "providerId": "basic-flow", 867 | "topLevel": false, 868 | "builtIn": true, 869 | "authenticationExecutions": [ 870 | { 871 | "authenticator": "idp-confirm-link", 872 | "requirement": "REQUIRED", 873 | "priority": 10, 874 | "userSetupAllowed": false, 875 | "autheticatorFlow": false 876 | }, 877 | { 878 | "authenticator": "idp-email-verification", 879 | "requirement": "ALTERNATIVE", 880 | "priority": 20, 881 | "userSetupAllowed": false, 882 | "autheticatorFlow": false 883 | }, 884 | { 885 | "requirement": "ALTERNATIVE", 886 | "priority": 30, 887 | "flowAlias": "Verify Existing Account by Re-authentication", 888 | "userSetupAllowed": false, 889 | "autheticatorFlow": true 890 | } 891 | ] 892 | }, 893 | { 894 | "id": "b0dd4f26-56c1-481b-a449-0da91c9f7786", 895 | "alias": "Verify Existing Account by Re-authentication", 896 | "description": "Reauthentication of existing account", 897 | "providerId": "basic-flow", 898 | "topLevel": false, 899 | "builtIn": true, 900 | "authenticationExecutions": [ 901 | { 902 | "authenticator": "idp-username-password-form", 903 | "requirement": "REQUIRED", 904 | "priority": 10, 905 | "userSetupAllowed": false, 906 | "autheticatorFlow": false 907 | }, 908 | { 909 | "authenticator": "auth-otp-form", 910 | "requirement": "OPTIONAL", 911 | "priority": 20, 912 | "userSetupAllowed": false, 913 | "autheticatorFlow": false 914 | } 915 | ] 916 | }, 917 | { 918 | "id": "f3f37e12-9278-4698-9325-3b6df15ab876", 919 | "alias": "browser", 920 | "description": "browser based authentication", 921 | "providerId": "basic-flow", 922 | "topLevel": true, 923 | "builtIn": true, 924 | "authenticationExecutions": [ 925 | { 926 | "authenticator": "auth-cookie", 927 | "requirement": "ALTERNATIVE", 928 | "priority": 10, 929 | "userSetupAllowed": false, 930 | "autheticatorFlow": false 931 | }, 932 | { 933 | "authenticator": "auth-spnego", 934 | "requirement": "DISABLED", 935 | "priority": 20, 936 | "userSetupAllowed": false, 937 | "autheticatorFlow": false 938 | }, 939 | { 940 | "authenticator": "identity-provider-redirector", 941 | "requirement": "ALTERNATIVE", 942 | "priority": 25, 943 | "userSetupAllowed": false, 944 | "autheticatorFlow": false 945 | }, 946 | { 947 | "requirement": "ALTERNATIVE", 948 | "priority": 30, 949 | "flowAlias": "forms", 950 | "userSetupAllowed": false, 951 | "autheticatorFlow": true 952 | } 953 | ] 954 | }, 955 | { 956 | "id": "a6938592-710c-4dcb-ba04-f6694d2ab1c9", 957 | "alias": "clients", 958 | "description": "Base authentication for clients", 959 | "providerId": "client-flow", 960 | "topLevel": true, 961 | "builtIn": true, 962 | "authenticationExecutions": [ 963 | { 964 | "authenticator": "client-secret", 965 | "requirement": "ALTERNATIVE", 966 | "priority": 10, 967 | "userSetupAllowed": false, 968 | "autheticatorFlow": false 969 | }, 970 | { 971 | "authenticator": "client-jwt", 972 | "requirement": "ALTERNATIVE", 973 | "priority": 20, 974 | "userSetupAllowed": false, 975 | "autheticatorFlow": false 976 | }, 977 | { 978 | "authenticator": "client-secret-jwt", 979 | "requirement": "ALTERNATIVE", 980 | "priority": 30, 981 | "userSetupAllowed": false, 982 | "autheticatorFlow": false 983 | }, 984 | { 985 | "authenticator": "client-x509", 986 | "requirement": "ALTERNATIVE", 987 | "priority": 40, 988 | "userSetupAllowed": false, 989 | "autheticatorFlow": false 990 | } 991 | ] 992 | }, 993 | { 994 | "id": "b9afd41f-5bd8-48ea-b063-fc4843409988", 995 | "alias": "direct grant", 996 | "description": "OpenID Connect Resource Owner Grant", 997 | "providerId": "basic-flow", 998 | "topLevel": true, 999 | "builtIn": true, 1000 | "authenticationExecutions": [ 1001 | { 1002 | "authenticator": "direct-grant-validate-username", 1003 | "requirement": "REQUIRED", 1004 | "priority": 10, 1005 | "userSetupAllowed": false, 1006 | "autheticatorFlow": false 1007 | }, 1008 | { 1009 | "authenticator": "direct-grant-validate-password", 1010 | "requirement": "REQUIRED", 1011 | "priority": 20, 1012 | "userSetupAllowed": false, 1013 | "autheticatorFlow": false 1014 | }, 1015 | { 1016 | "authenticator": "direct-grant-validate-otp", 1017 | "requirement": "OPTIONAL", 1018 | "priority": 30, 1019 | "userSetupAllowed": false, 1020 | "autheticatorFlow": false 1021 | } 1022 | ] 1023 | }, 1024 | { 1025 | "id": "b9c9baab-b628-4107-9efb-5b9bc0c52250", 1026 | "alias": "docker auth", 1027 | "description": "Used by Docker clients to authenticate against the IDP", 1028 | "providerId": "basic-flow", 1029 | "topLevel": true, 1030 | "builtIn": true, 1031 | "authenticationExecutions": [ 1032 | { 1033 | "authenticator": "docker-http-basic-authenticator", 1034 | "requirement": "REQUIRED", 1035 | "priority": 10, 1036 | "userSetupAllowed": false, 1037 | "autheticatorFlow": false 1038 | } 1039 | ] 1040 | }, 1041 | { 1042 | "id": "10ecd348-e5d5-43c3-b1f4-43d70e612656", 1043 | "alias": "first broker login", 1044 | "description": "Actions taken after first broker login with identity provider account, which is not yet linked to any Keycloak account", 1045 | "providerId": "basic-flow", 1046 | "topLevel": true, 1047 | "builtIn": true, 1048 | "authenticationExecutions": [ 1049 | { 1050 | "authenticatorConfig": "review profile config", 1051 | "authenticator": "idp-review-profile", 1052 | "requirement": "REQUIRED", 1053 | "priority": 10, 1054 | "userSetupAllowed": false, 1055 | "autheticatorFlow": false 1056 | }, 1057 | { 1058 | "authenticatorConfig": "create unique user config", 1059 | "authenticator": "idp-create-user-if-unique", 1060 | "requirement": "ALTERNATIVE", 1061 | "priority": 20, 1062 | "userSetupAllowed": false, 1063 | "autheticatorFlow": false 1064 | }, 1065 | { 1066 | "requirement": "ALTERNATIVE", 1067 | "priority": 30, 1068 | "flowAlias": "Handle Existing Account", 1069 | "userSetupAllowed": false, 1070 | "autheticatorFlow": true 1071 | } 1072 | ] 1073 | }, 1074 | { 1075 | "id": "563074c8-0d05-455a-9db5-cd6be88f2d8b", 1076 | "alias": "forms", 1077 | "description": "Username, password, otp and other auth forms.", 1078 | "providerId": "basic-flow", 1079 | "topLevel": false, 1080 | "builtIn": true, 1081 | "authenticationExecutions": [ 1082 | { 1083 | "authenticator": "auth-username-password-form", 1084 | "requirement": "REQUIRED", 1085 | "priority": 10, 1086 | "userSetupAllowed": false, 1087 | "autheticatorFlow": false 1088 | }, 1089 | { 1090 | "authenticator": "auth-otp-form", 1091 | "requirement": "OPTIONAL", 1092 | "priority": 20, 1093 | "userSetupAllowed": false, 1094 | "autheticatorFlow": false 1095 | } 1096 | ] 1097 | }, 1098 | { 1099 | "id": "68a05a04-615b-420f-8105-231d51e68e5a", 1100 | "alias": "http challenge", 1101 | "description": "An authentication flow based on challenge-response HTTP Authentication Schemes", 1102 | "providerId": "basic-flow", 1103 | "topLevel": true, 1104 | "builtIn": true, 1105 | "authenticationExecutions": [ 1106 | { 1107 | "authenticator": "no-cookie-redirect", 1108 | "requirement": "REQUIRED", 1109 | "priority": 10, 1110 | "userSetupAllowed": false, 1111 | "autheticatorFlow": false 1112 | }, 1113 | { 1114 | "authenticator": "basic-auth", 1115 | "requirement": "REQUIRED", 1116 | "priority": 20, 1117 | "userSetupAllowed": false, 1118 | "autheticatorFlow": false 1119 | }, 1120 | { 1121 | "authenticator": "basic-auth-otp", 1122 | "requirement": "DISABLED", 1123 | "priority": 30, 1124 | "userSetupAllowed": false, 1125 | "autheticatorFlow": false 1126 | }, 1127 | { 1128 | "authenticator": "auth-spnego", 1129 | "requirement": "DISABLED", 1130 | "priority": 40, 1131 | "userSetupAllowed": false, 1132 | "autheticatorFlow": false 1133 | } 1134 | ] 1135 | }, 1136 | { 1137 | "id": "413a36ca-337b-488b-957b-9972885d3a81", 1138 | "alias": "registration", 1139 | "description": "registration flow", 1140 | "providerId": "basic-flow", 1141 | "topLevel": true, 1142 | "builtIn": true, 1143 | "authenticationExecutions": [ 1144 | { 1145 | "authenticator": "registration-page-form", 1146 | "requirement": "REQUIRED", 1147 | "priority": 10, 1148 | "flowAlias": "registration form", 1149 | "userSetupAllowed": false, 1150 | "autheticatorFlow": true 1151 | } 1152 | ] 1153 | }, 1154 | { 1155 | "id": "e0433126-ed43-4d30-89a0-f1f123b6751d", 1156 | "alias": "registration form", 1157 | "description": "registration form", 1158 | "providerId": "form-flow", 1159 | "topLevel": false, 1160 | "builtIn": true, 1161 | "authenticationExecutions": [ 1162 | { 1163 | "authenticator": "registration-user-creation", 1164 | "requirement": "REQUIRED", 1165 | "priority": 20, 1166 | "userSetupAllowed": false, 1167 | "autheticatorFlow": false 1168 | }, 1169 | { 1170 | "authenticator": "registration-profile-action", 1171 | "requirement": "REQUIRED", 1172 | "priority": 40, 1173 | "userSetupAllowed": false, 1174 | "autheticatorFlow": false 1175 | }, 1176 | { 1177 | "authenticator": "registration-password-action", 1178 | "requirement": "REQUIRED", 1179 | "priority": 50, 1180 | "userSetupAllowed": false, 1181 | "autheticatorFlow": false 1182 | }, 1183 | { 1184 | "authenticator": "registration-recaptcha-action", 1185 | "requirement": "DISABLED", 1186 | "priority": 60, 1187 | "userSetupAllowed": false, 1188 | "autheticatorFlow": false 1189 | } 1190 | ] 1191 | }, 1192 | { 1193 | "id": "15891a73-d2a5-4b49-96b3-57dbf165580d", 1194 | "alias": "reset credentials", 1195 | "description": "Reset credentials for a user if they forgot their password or something", 1196 | "providerId": "basic-flow", 1197 | "topLevel": true, 1198 | "builtIn": true, 1199 | "authenticationExecutions": [ 1200 | { 1201 | "authenticator": "reset-credentials-choose-user", 1202 | "requirement": "REQUIRED", 1203 | "priority": 10, 1204 | "userSetupAllowed": false, 1205 | "autheticatorFlow": false 1206 | }, 1207 | { 1208 | "authenticator": "reset-credential-email", 1209 | "requirement": "REQUIRED", 1210 | "priority": 20, 1211 | "userSetupAllowed": false, 1212 | "autheticatorFlow": false 1213 | }, 1214 | { 1215 | "authenticator": "reset-password", 1216 | "requirement": "REQUIRED", 1217 | "priority": 30, 1218 | "userSetupAllowed": false, 1219 | "autheticatorFlow": false 1220 | }, 1221 | { 1222 | "authenticator": "reset-otp", 1223 | "requirement": "OPTIONAL", 1224 | "priority": 40, 1225 | "userSetupAllowed": false, 1226 | "autheticatorFlow": false 1227 | } 1228 | ] 1229 | }, 1230 | { 1231 | "id": "41751105-1c1c-4d07-85ac-d5b37fca8184", 1232 | "alias": "saml ecp", 1233 | "description": "SAML ECP Profile Authentication Flow", 1234 | "providerId": "basic-flow", 1235 | "topLevel": true, 1236 | "builtIn": true, 1237 | "authenticationExecutions": [ 1238 | { 1239 | "authenticator": "http-basic-authenticator", 1240 | "requirement": "REQUIRED", 1241 | "priority": 10, 1242 | "userSetupAllowed": false, 1243 | "autheticatorFlow": false 1244 | } 1245 | ] 1246 | } 1247 | ], 1248 | "authenticatorConfig": [ 1249 | { 1250 | "id": "4904013c-ddd9-4f36-a376-eb00a0e903da", 1251 | "alias": "create unique user config", 1252 | "config": { 1253 | "require.password.update.after.registration": "false" 1254 | } 1255 | }, 1256 | { 1257 | "id": "b49aa53d-ff4b-41dd-bcba-6f1b779d7c1f", 1258 | "alias": "review profile config", 1259 | "config": { 1260 | "update.profile.on.first.login": "missing" 1261 | } 1262 | } 1263 | ], 1264 | "requiredActions": [ 1265 | { 1266 | "alias": "CONFIGURE_TOTP", 1267 | "name": "Configure OTP", 1268 | "providerId": "CONFIGURE_TOTP", 1269 | "enabled": true, 1270 | "defaultAction": false, 1271 | "priority": 10, 1272 | "config": {} 1273 | }, 1274 | { 1275 | "alias": "terms_and_conditions", 1276 | "name": "Terms and Conditions", 1277 | "providerId": "terms_and_conditions", 1278 | "enabled": false, 1279 | "defaultAction": false, 1280 | "priority": 20, 1281 | "config": {} 1282 | }, 1283 | { 1284 | "alias": "UPDATE_PASSWORD", 1285 | "name": "Update Password", 1286 | "providerId": "UPDATE_PASSWORD", 1287 | "enabled": true, 1288 | "defaultAction": false, 1289 | "priority": 30, 1290 | "config": {} 1291 | }, 1292 | { 1293 | "alias": "UPDATE_PROFILE", 1294 | "name": "Update Profile", 1295 | "providerId": "UPDATE_PROFILE", 1296 | "enabled": true, 1297 | "defaultAction": false, 1298 | "priority": 40, 1299 | "config": {} 1300 | }, 1301 | { 1302 | "alias": "VERIFY_EMAIL", 1303 | "name": "Verify Email", 1304 | "providerId": "VERIFY_EMAIL", 1305 | "enabled": true, 1306 | "defaultAction": false, 1307 | "priority": 50, 1308 | "config": {} 1309 | } 1310 | ], 1311 | "browserFlow": "browser", 1312 | "registrationFlow": "registration", 1313 | "directGrantFlow": "direct grant", 1314 | "resetCredentialsFlow": "reset credentials", 1315 | "clientAuthenticationFlow": "clients", 1316 | "dockerAuthenticationFlow": "docker auth", 1317 | "attributes": { 1318 | "_browser_header.xXSSProtection": "1; mode=block", 1319 | "_browser_header.xFrameOptions": "SAMEORIGIN", 1320 | "_browser_header.strictTransportSecurity": "max-age=31536000; includeSubDomains", 1321 | "permanentLockout": "false", 1322 | "quickLoginCheckMilliSeconds": "1000", 1323 | "_browser_header.xRobotsTag": "none", 1324 | "maxFailureWaitSeconds": "900", 1325 | "minimumQuickLoginWaitSeconds": "60", 1326 | "failureFactor": "30", 1327 | "actionTokenGeneratedByUserLifespan": "300", 1328 | "maxDeltaTimeSeconds": "43200", 1329 | "_browser_header.xContentTypeOptions": "nosniff", 1330 | "offlineSessionMaxLifespan": "5184000", 1331 | "actionTokenGeneratedByAdminLifespan": "43200", 1332 | "_browser_header.contentSecurityPolicyReportOnly": "", 1333 | "bruteForceProtected": "false", 1334 | "_browser_header.contentSecurityPolicy": "frame-src 'self'; frame-ancestors 'self'; object-src 'none';", 1335 | "waitIncrementSeconds": "60", 1336 | "offlineSessionMaxLifespanEnabled": "false" 1337 | }, 1338 | "keycloakVersion": "4.5.0.Final", 1339 | "userManagedAccessAllowed": false 1340 | } -------------------------------------------------------------------------------- /keycloak/services.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | labels: 5 | app: keycloak 6 | name: keycloak-headless 7 | spec: 8 | clusterIP: None 9 | ports: 10 | - name: http 11 | port: 80 12 | protocol: TCP 13 | targetPort: http 14 | selector: 15 | app: keycloak 16 | type: ClusterIP 17 | 18 | --- 19 | 20 | apiVersion: v1 21 | kind: Service 22 | metadata: 23 | labels: 24 | app: keycloak 25 | name: keycloak-http 26 | spec: 27 | ports: 28 | - name: http 29 | port: 80 30 | protocol: TCP 31 | targetPort: http 32 | selector: 33 | app: keycloak 34 | type: ClusterIP 35 | -------------------------------------------------------------------------------- /keycloak/statefulset.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: StatefulSet 3 | metadata: 4 | labels: 5 | app: keycloak 6 | name: keycloak 7 | spec: 8 | podManagementPolicy: Parallel 9 | replicas: 1 10 | selector: 11 | matchLabels: 12 | app: keycloak 13 | serviceName: keycloak-headless 14 | template: 15 | metadata: 16 | labels: 17 | app: keycloak 18 | spec: 19 | affinity: 20 | podAntiAffinity: 21 | preferredDuringSchedulingIgnoredDuringExecution: 22 | - podAffinityTerm: 23 | labelSelector: 24 | matchExpressions: 25 | - key: role 26 | operator: NotIn 27 | values: 28 | - test 29 | matchLabels: 30 | app: keycloak 31 | release: keycloak 32 | topologyKey: failure-domain.beta.kubernetes.io/zone 33 | weight: 100 34 | requiredDuringSchedulingIgnoredDuringExecution: 35 | - labelSelector: 36 | matchExpressions: 37 | - key: role 38 | operator: NotIn 39 | values: 40 | - test 41 | matchLabels: 42 | app: keycloak 43 | release: keycloak 44 | topologyKey: kubernetes.io/hostname 45 | initContainers: 46 | - name: wait-for-postgresql 47 | image: alpine:3.8 48 | command: 49 | - sh 50 | - -c 51 | - | 52 | until printf "." && nc -z -w 2 $(POSTGRESQL) 5432; do 53 | sleep 2; 54 | done; 55 | 56 | echo 'PostgreSQL OK ✓' 57 | containers: 58 | - command: 59 | - /scripts/keycloak.sh 60 | env: 61 | - name: KEYCLOAK_USER 62 | value: keycloak 63 | - name: KEYCLOAK_PASSWORD 64 | valueFrom: 65 | secretKeyRef: 66 | key: password 67 | name: keycloak-http 68 | - name: DB_VENDOR 69 | value: postgres 70 | - name: DB_ADDR 71 | value: $(POSTGRESQL) 72 | - name: DB_PORT 73 | value: "5432" 74 | - name: DB_DATABASE 75 | value: keycloak 76 | - name: DB_USER 77 | value: keycloak 78 | - name: DB_PASSWORD 79 | valueFrom: 80 | secretKeyRef: 81 | name: postgresql 82 | key: postgres-password 83 | - name: KEYCLOAK_IMPORT 84 | value: /realm/realm-export.json 85 | image: jboss/keycloak:11.0.2 86 | livenessProbe: 87 | httpGet: 88 | path: /auth/ 89 | port: http 90 | scheme: HTTP 91 | initialDelaySeconds: 120 92 | timeoutSeconds: 5 93 | name: keycloak 94 | ports: 95 | - containerPort: 8080 96 | name: http 97 | protocol: TCP 98 | readinessProbe: 99 | httpGet: 100 | path: /auth/realms/master 101 | port: http 102 | scheme: HTTP 103 | initialDelaySeconds: 30 104 | volumeMounts: 105 | - mountPath: /scripts 106 | name: scripts 107 | - mountPath: /realm 108 | name: realm-export 109 | securityContext: 110 | fsGroup: 1000 111 | runAsNonRoot: true 112 | runAsUser: 1000 113 | volumes: 114 | - configMap: 115 | defaultMode: 365 116 | name: keycloak 117 | name: scripts 118 | - configMap: 119 | name: realm-export 120 | name: realm-export 121 | volumeClaimTemplates: [] 122 | -------------------------------------------------------------------------------- /kustomization.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kustomize.config.k8s.io/v1beta1 2 | kind: Kustomization 3 | 4 | bases: 5 | - nginx-ingress 6 | - logging 7 | - metrics 8 | - keycloak 9 | - postgresql 10 | 11 | resources: 12 | - cert-manager/deployment.yaml 13 | - cert-manager/sa.yaml 14 | - cert-manager/crds.yaml 15 | - cert-manager/rbac.yaml 16 | - cert-manager/cluster-issuer.yaml 17 | 18 | - external-dns/deployment.yaml 19 | - external-dns/sa.yaml 20 | - external-dns/rbac.yaml 21 | 22 | - oauth2-proxy/deployment.yaml 23 | - oauth2-proxy/hpa.yaml 24 | - oauth2-proxy/service.yaml 25 | 26 | vars: 27 | # this VAR reference needs a CM defined in the overlay kustomization.yaml 28 | - name: PLATFORM_CONFIG_DOMAIN 29 | objref: 30 | kind: ConfigMap 31 | name: kubeplatform-config 32 | apiVersion: v1 33 | fieldref: 34 | fieldpath: data.DOMAIN 35 | 36 | commonLabels: 37 | kubeplatform: v1 38 | -------------------------------------------------------------------------------- /logging/curator/action_file.yaml: -------------------------------------------------------------------------------- 1 | actions: 2 | 1: 3 | action: delete_indices 4 | description: "Clean up ES by deleting old indices" 5 | options: 6 | timeout_override: 7 | continue_if_exception: False 8 | disable_action: False 9 | ignore_empty_list: True 10 | filters: 11 | - filtertype: age 12 | source: name 13 | direction: older 14 | timestring: '%Y.%m.%d' 15 | unit: days 16 | unit_count: 3 17 | field: 18 | stats_result: 19 | epoch: 20 | exclude: False 21 | -------------------------------------------------------------------------------- /logging/curator/config.yaml: -------------------------------------------------------------------------------- 1 | client: 2 | hosts: 3 | - ${ES_SERVICE_NAME} 4 | port: 9200 5 | -------------------------------------------------------------------------------- /logging/curator/cronjob.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: batch/v1beta1 2 | kind: CronJob 3 | metadata: 4 | name: elasticsearch-curator 5 | labels: 6 | app: elasticsearch-curator 7 | release: 5.7.6 8 | spec: 9 | schedule: "0 1 * * *" 10 | jobTemplate: 11 | metadata: 12 | labels: 13 | app: elasticsearch-curator 14 | release: 5.7.6 15 | spec: 16 | template: 17 | metadata: 18 | labels: 19 | app: elasticsearch-curator 20 | release: 5.7.6 21 | spec: 22 | volumes: 23 | - name: config-volume 24 | configMap: 25 | name: elasticsearch-curator-config 26 | restartPolicy: Never 27 | containers: 28 | - name: elasticsearch-curator 29 | image: untergeek/curator:5.8.1 30 | args: [ "--config", "/etc/es-curator/config.yaml", "/etc/es-curator/action_file.yaml" ] 31 | volumeMounts: 32 | - name: config-volume 33 | mountPath: /etc/es-curator 34 | env: 35 | - name: ES_SERVICE_NAME 36 | value: $(ES_SERVICE_NAME) 37 | -------------------------------------------------------------------------------- /logging/curator/kustomization.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kustomize.config.k8s.io/v1beta1 2 | kind: Kustomization 3 | 4 | resources: 5 | - cronjob.yaml 6 | 7 | configMapGenerator: 8 | - name: elasticsearch-curator-config 9 | files: 10 | - action_file.yaml 11 | - config.yaml 12 | 13 | vars: 14 | - name: ES_SERVICE_NAME 15 | objref: 16 | kind: Service 17 | name: elasticsearch-logging 18 | apiVersion: v1 -------------------------------------------------------------------------------- /logging/elasticsearch/java.security: -------------------------------------------------------------------------------- 1 | # 2 | # This is an alternate "security properties file". 3 | # 4 | # An alternate java.security properties file may be specified 5 | # from the command line via the system property 6 | # 7 | # -Djava.security.properties= 8 | # 9 | 10 | # The JVM defaults to caching positive hostname resolutions indefinitely. 11 | # Elasticsearch nodes rely on DNS (Kubernetes headless service), where DNS 12 | # resolutions vary with time (e.g., for node-to-node discovery). This 13 | # behaviour can be modified by adding networkaddress.cache.ttl= 14 | # to an alternate Java security properties file. 15 | # https://www.elastic.co/guide/en/elasticsearch/reference/6.3/networkaddress-cache-ttl.html 16 | networkaddress.cache.ttl=60 -------------------------------------------------------------------------------- /logging/elasticsearch/kustomization.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kustomize.config.k8s.io/v1beta1 2 | kind: Kustomization 3 | 4 | resources: 5 | - sa.yaml 6 | - service.yaml 7 | - statefulset.yaml 8 | - rbac.yaml 9 | 10 | configMapGenerator: 11 | - name: java-elasticsearch-logging 12 | files: 13 | - java.security 14 | -------------------------------------------------------------------------------- /logging/elasticsearch/rbac.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1 2 | kind: ClusterRole 3 | metadata: 4 | labels: 5 | k8s-app: elasticsearch-logging 6 | name: elasticsearch-logging 7 | rules: 8 | - apiGroups: 9 | - "" 10 | resources: 11 | - services 12 | - namespaces 13 | - endpoints 14 | verbs: 15 | - get 16 | 17 | --- 18 | 19 | apiVersion: rbac.authorization.k8s.io/v1 20 | kind: ClusterRoleBinding 21 | metadata: 22 | labels: 23 | k8s-app: elasticsearch-logging 24 | name: elasticsearch-logging 25 | roleRef: 26 | apiGroup: rbac.authorization.k8s.io 27 | kind: ClusterRole 28 | name: elasticsearch-logging 29 | subjects: 30 | - kind: ServiceAccount 31 | name: elasticsearch-logging 32 | namespace: kubeplatform 33 | -------------------------------------------------------------------------------- /logging/elasticsearch/sa.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ServiceAccount 3 | metadata: 4 | labels: 5 | k8s-app: elasticsearch-logging 6 | name: elasticsearch-logging 7 | -------------------------------------------------------------------------------- /logging/elasticsearch/service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | annotations: 5 | service.alpha.kubernetes.io/tolerate-unready-endpoints: "true" 6 | labels: 7 | k8s-app: elasticsearch-logging 8 | kubernetes.io/name: Elasticsearch 9 | name: elasticsearch-logging 10 | spec: 11 | clusterIP: None 12 | ports: 13 | - name: db 14 | port: 9200 15 | protocol: TCP 16 | targetPort: 9200 17 | publishNotReadyAddresses: true 18 | selector: 19 | k8s-app: elasticsearch-logging 20 | name: elasticsearch-logging 21 | type: ClusterIP -------------------------------------------------------------------------------- /logging/elasticsearch/statefulset.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: StatefulSet 3 | metadata: 4 | labels: 5 | k8s-app: elasticsearch-logging 6 | name: elasticsearch-logging 7 | spec: 8 | podManagementPolicy: Parallel 9 | replicas: 3 10 | selector: 11 | matchLabels: 12 | k8s-app: elasticsearch-logging 13 | name: elasticsearch-logging 14 | serviceName: elasticsearch-logging 15 | template: 16 | metadata: 17 | annotations: 18 | prometheus.io/port: "9102" 19 | prometheus.io/scrape: "true" 20 | labels: 21 | k8s-app: elasticsearch-logging 22 | name: elasticsearch-logging 23 | spec: 24 | affinity: 25 | podAntiAffinity: 26 | preferredDuringSchedulingIgnoredDuringExecution: 27 | - podAffinityTerm: 28 | labelSelector: 29 | matchLabels: 30 | k8s-app: elasticsearch-logging 31 | name: elasticsearch-logging 32 | topologyKey: failure-domain.beta.kubernetes.io/zone 33 | weight: 50 34 | - podAffinityTerm: 35 | labelSelector: 36 | matchLabels: 37 | k8s-app: elasticsearch-logging 38 | name: elasticsearch-logging 39 | topologyKey: kubernetes.io/hostname 40 | weight: 100 41 | containers: 42 | - name: elasticsearch-logging 43 | env: 44 | - name: ELASTICSEARCH_CLUSTER_HOSTS 45 | value: $(ELASTICSEARCH_LOGGING) 46 | - name: ELASTICSEARCH_CLUSTER_NAME 47 | value: elasticsearch-cluster 48 | - name: ELASTICSEARCH_MINIMUM_MASTER_NODES 49 | value: "2" 50 | - name: ELASTICSEARCH_NODE_PORT_NUMBER 51 | value: "9300" 52 | - name: ELASTICSEARCH_PORT_NUMBER 53 | value: "9200" 54 | - name: ES_JAVA_OPTS 55 | value: 56 | -Djava.security.properties=/opt/bitnami/java/lib/security/java.security.custom 57 | -Xms1200m -Xmx1200m -XshowSettings:vm 58 | image: bitnami/elasticsearch:6.8.12 59 | livenessProbe: 60 | httpGet: 61 | path: /_cluster/health?local=true 62 | port: db 63 | scheme: HTTP 64 | initialDelaySeconds: 180 65 | ports: 66 | - containerPort: 9200 67 | name: db 68 | protocol: TCP 69 | - containerPort: 9300 70 | name: transport 71 | protocol: TCP 72 | readinessProbe: 73 | httpGet: 74 | path: /_cluster/health?local=true 75 | port: db 76 | scheme: HTTP 77 | initialDelaySeconds: 120 78 | resources: 79 | limits: 80 | memory: 2Gi 81 | requests: 82 | memory: 2Gi 83 | securityContext: 84 | runAsUser: 1001 85 | volumeMounts: 86 | - mountPath: /bitnami/elasticsearch/data 87 | name: data 88 | - mountPath: /opt/bitnami/java/lib/security/java.security.custom 89 | name: java-security 90 | readOnly: true 91 | subPath: java.security 92 | - args: 93 | - --es.all=false 94 | - --es.timeout=20s 95 | - --es.uri=http://localhost:9200/ 96 | - --web.listen-address=:9102 97 | - --web.telemetry-path=/metrics 98 | command: 99 | - elasticsearch_exporter 100 | image: justwatch/elasticsearch_exporter:1.0.1 101 | livenessProbe: 102 | httpGet: 103 | path: / 104 | port: metrics 105 | scheme: HTTP 106 | name: prom-exporter 107 | ports: 108 | - containerPort: 9102 109 | name: metrics 110 | protocol: TCP 111 | initContainers: 112 | - command: 113 | - /sbin/sysctl 114 | - -w 115 | - vm.max_map_count=262144 116 | image: alpine:3.6 117 | name: elasticsearch-logging-init 118 | securityContext: 119 | privileged: true 120 | securityContext: 121 | fsGroup: 1001 122 | serviceAccountName: elasticsearch-logging 123 | terminationGracePeriodSeconds: 300 124 | volumes: 125 | - configMap: 126 | defaultMode: 420 127 | name: java-elasticsearch-logging 128 | name: java-security 129 | volumeClaimTemplates: 130 | - metadata: 131 | labels: 132 | name: data 133 | name: data 134 | spec: 135 | accessModes: 136 | - ReadWriteOnce 137 | resources: 138 | requests: 139 | storage: 100Gi 140 | -------------------------------------------------------------------------------- /logging/fluentd/containers.input.conf: -------------------------------------------------------------------------------- 1 | # This configuration file for Fluentd / td-agent is used 2 | # to watch changes to Docker log files. The kubelet creates symlinks that 3 | # capture the pod name, namespace, container name & Docker container ID 4 | # to the docker logs for pods in the /var/log/containers directory on the host. 5 | # If running this fluentd configuration in a Docker container, the /var/log 6 | # directory should be mounted in the container. 7 | # 8 | # These logs are then submitted to Elasticsearch which assumes the 9 | # installation of the fluent-plugin-elasticsearch & the 10 | # fluent-plugin-kubernetes_metadata_filter plugins. 11 | # See https://github.com/uken/fluent-plugin-elasticsearch & 12 | # https://github.com/fabric8io/fluent-plugin-kubernetes_metadata_filter for 13 | # more information about the plugins. 14 | # 15 | # Example 16 | # ======= 17 | # A line in the Docker log file might look like this JSON: 18 | # 19 | # {"log":"2014/09/25 21:15:03 Got request with path wombat\n", 20 | # "stream":"stderr", 21 | # "time":"2014-09-25T21:15:03.499185026Z"} 22 | # 23 | # The time_format specification below makes sure we properly 24 | # parse the time format produced by Docker. This will be 25 | # submitted to Elasticsearch and should appear like: 26 | # $ curl 'http://elasticsearch-logging:9200/_search?pretty' 27 | # ... 28 | # { 29 | # "_index" : "logstash-2014.09.25", 30 | # "_type" : "fluentd", 31 | # "_id" : "VBrbor2QTuGpsQyTCdfzqA", 32 | # "_score" : 1.0, 33 | # "_source":{"log":"2014/09/25 22:45:50 Got request with path wombat\n", 34 | # "stream":"stderr","tag":"docker.container.all", 35 | # "@timestamp":"2014-09-25T22:45:50+00:00"} 36 | # }, 37 | # ... 38 | # 39 | # The Kubernetes fluentd plugin is used to write the Kubernetes metadata to the log 40 | # record & add labels to the log record if properly configured. This enables users 41 | # to filter & search logs on any metadata. 42 | # For example a Docker container's logs might be in the directory: 43 | # 44 | # /var/lib/docker/containers/997599971ee6366d4a5920d25b79286ad45ff37a74494f262e3bc98d909d0a7b 45 | # 46 | # and in the file: 47 | # 48 | # 997599971ee6366d4a5920d25b79286ad45ff37a74494f262e3bc98d909d0a7b-json.log 49 | # 50 | # where 997599971ee6... is the Docker ID of the running container. 51 | # The Kubernetes kubelet makes a symbolic link to this file on the host machine 52 | # in the /var/log/containers directory which includes the pod name and the Kubernetes 53 | # container name: 54 | # 55 | # synthetic-logger-0.25lps-pod_default_synth-lgr-997599971ee6366d4a5920d25b79286ad45ff37a74494f262e3bc98d909d0a7b.log 56 | # -> 57 | # /var/lib/docker/containers/997599971ee6366d4a5920d25b79286ad45ff37a74494f262e3bc98d909d0a7b/997599971ee6366d4a5920d25b79286ad45ff37a74494f262e3bc98d909d0a7b-json.log 58 | # 59 | # The /var/log directory on the host is mapped to the /var/log directory in the container 60 | # running this instance of Fluentd and we end up collecting the file: 61 | # 62 | # /var/log/containers/synthetic-logger-0.25lps-pod_default_synth-lgr-997599971ee6366d4a5920d25b79286ad45ff37a74494f262e3bc98d909d0a7b.log 63 | # 64 | # This results in the tag: 65 | # 66 | # var.log.containers.synthetic-logger-0.25lps-pod_default_synth-lgr-997599971ee6366d4a5920d25b79286ad45ff37a74494f262e3bc98d909d0a7b.log 67 | # 68 | # The Kubernetes fluentd plugin is used to extract the namespace, pod name & container name 69 | # which are added to the log message as a kubernetes field object & the Docker container ID 70 | # is also added under the docker field object. 71 | # The final tag is: 72 | # 73 | # kubernetes.var.log.containers.synthetic-logger-0.25lps-pod_default_synth-lgr-997599971ee6366d4a5920d25b79286ad45ff37a74494f262e3bc98d909d0a7b.log 74 | # 75 | # And the final log record look like: 76 | # 77 | # { 78 | # "log":"2014/09/25 21:15:03 Got request with path wombat\n", 79 | # "stream":"stderr", 80 | # "time":"2014-09-25T21:15:03.499185026Z", 81 | # "kubernetes": { 82 | # "namespace": "default", 83 | # "pod_name": "synthetic-logger-0.25lps-pod", 84 | # "container_name": "synth-lgr" 85 | # }, 86 | # "docker": { 87 | # "container_id": "997599971ee6366d4a5920d25b79286ad45ff37a74494f262e3bc98d909d0a7b" 88 | # } 89 | # } 90 | # 91 | # This makes it easier for users to search for logs by pod name or by 92 | # the name of the Kubernetes container regardless of how many times the 93 | # Kubernetes pod has been restarted (resulting in a several Docker container IDs). 94 | 95 | # Json Log Example: 96 | # {"log":"[info:2016-02-16T16:04:05.930-08:00] Some log text here\n","stream":"stdout","time":"2016-02-17T00:04:05.931087621Z"} 97 | # CRI Log Example: 98 | # 2016-02-17T00:04:05.931087621Z stdout F [info:2016-02-16T16:04:05.930-08:00] Some log text here 99 | 100 | @id fluentd-containers.log 101 | @type tail 102 | path /var/log/containers/*.log 103 | pos_file /var/log/fluentd-pos/es-containers.log.pos 104 | tag raw.kubernetes.* 105 | read_from_head true 106 | 107 | @type multi_format 108 | 109 | format json 110 | time_key time 111 | time_format %Y-%m-%dT%H:%M:%S.%NZ 112 | 113 | 114 | format /^(? 117 | 118 | 119 | 120 | # Detect exceptions in the log output and forward them as one log entry. 121 | 122 | @id raw.kubernetes 123 | @type detect_exceptions 124 | remove_tag_prefix raw 125 | message log 126 | stream stream 127 | multiline_flush_interval 5 128 | max_bytes 500000 129 | max_lines 1000 130 | -------------------------------------------------------------------------------- /logging/fluentd/ds.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: DaemonSet 3 | metadata: 4 | name: fluentd-es 5 | spec: 6 | selector: 7 | matchLabels: 8 | name: fluentd-es 9 | template: 10 | metadata: 11 | annotations: 12 | prometheus.io/path: /metrics 13 | prometheus.io/port: "24231" 14 | prometheus.io/scrape: "true" 15 | scheduler.alpha.kubernetes.io/critical-pod: "" 16 | labels: 17 | name: fluentd-es 18 | spec: 19 | securityContext: 20 | runAsUser: 0 21 | runAsGroup: 0 22 | fsGroup: 0 23 | containers: 24 | - env: 25 | - name: ES_HOST 26 | value: $(ELASTICSEARCH_LOGGING) 27 | - name: FLUENTD_OPT 28 | value: -o /opt/bitnami/fluentd/logs/fluentd.log --log-rotate-age 5 --log-rotate-size 29 | 104857600 --no-supervisor 30 | image: bitnami/fluentd:1.3.3 31 | name: fluentd-es 32 | resources: 33 | limits: 34 | memory: 200Mi 35 | requests: 36 | memory: 200Mi 37 | securityContext: 38 | privileged: true 39 | capabilities: 40 | drop: ['ALL'] 41 | volumeMounts: 42 | - mountPath: /opt/bitnami/fluentd/conf 43 | name: config 44 | readOnly: true 45 | - mountPath: /opt/bitnami/fluentd/conf/config.d 46 | name: configd 47 | readOnly: true 48 | - mountPath: /var/lib/docker/containers 49 | name: varlibdockercontainers 50 | readOnly: true 51 | - mountPath: /var/log 52 | name: varlog 53 | readOnly: true 54 | - mountPath: /var/log/fluentd-buffers 55 | name: varlogbuffers 56 | - mountPath: /var/log/fluentd-pos 57 | name: varlogpos 58 | serviceAccountName: fluentd-es 59 | volumes: 60 | - configMap: 61 | defaultMode: 420 62 | name: fluentd-es 63 | name: config 64 | - configMap: 65 | defaultMode: 420 66 | name: fluentd-es-configd 67 | name: configd 68 | - hostPath: 69 | path: /var/lib/docker/containers 70 | type: Directory 71 | name: varlibdockercontainers 72 | - hostPath: 73 | path: /var/log 74 | type: Directory 75 | name: varlog 76 | - hostPath: 77 | path: /var/log/fluentd-buffers 78 | type: DirectoryOrCreate 79 | name: varlogbuffers 80 | - hostPath: 81 | path: /var/log/fluentd-pos 82 | type: DirectoryOrCreate 83 | name: varlogpos 84 | -------------------------------------------------------------------------------- /logging/fluentd/fluentd.conf: -------------------------------------------------------------------------------- 1 | # Include config files in the ./config.d directory 2 | @include config.d/*.conf -------------------------------------------------------------------------------- /logging/fluentd/kustomization.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kustomize.config.k8s.io/v1beta1 2 | kind: Kustomization 3 | 4 | resources: 5 | - ds.yaml 6 | - sa.yaml 7 | - rbac.yaml 8 | 9 | configMapGenerator: 10 | - name: fluentd-es-configd 11 | files: 12 | - containers.input.conf 13 | - monitoring.conf 14 | - system.input.conf 15 | - system.conf 16 | - name: fluentd-es 17 | files: 18 | - fluentd.conf -------------------------------------------------------------------------------- /logging/fluentd/monitoring.conf: -------------------------------------------------------------------------------- 1 | # Prometheus Exporter Plugin 2 | # input plugin that exports metrics 3 | 4 | @type prometheus 5 | 6 | 7 | 8 | @type monitor_agent 9 | 10 | 11 | # input plugin that collects metrics from MonitorAgent 12 | 13 | @type prometheus_monitor 14 | 15 | host ${hostname} 16 | 17 | 18 | 19 | # input plugin that collects metrics for output plugin 20 | 21 | @type prometheus_output_monitor 22 | 23 | host ${hostname} 24 | 25 | 26 | 27 | # input plugin that collects metrics for in_tail plugin 28 | 29 | @type prometheus_tail_monitor 30 | 31 | host ${hostname} 32 | 33 | 34 | output.conf: | 35 | # Enriches records with Kubernetes metadata 36 | 37 | @type kubernetes_metadata 38 | 39 | 40 | 41 | @id elasticsearch 42 | @type elasticsearch 43 | @log_level info 44 | type_name fluentd 45 | include_tag_key true 46 | host "#{ENV['ES_HOST']}" 47 | port 9200 48 | logstash_format true 49 | 50 | @type file 51 | path /var/log/fluentd-buffers/kubernetes.system.buffer 52 | flush_mode interval 53 | retry_type exponential_backoff 54 | flush_thread_count 2 55 | flush_interval 5s 56 | retry_forever 57 | retry_max_interval 30 58 | chunk_limit_size 2M 59 | queue_limit_length 8 60 | overflow_action block 61 | 62 | -------------------------------------------------------------------------------- /logging/fluentd/rbac.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1 2 | kind: ClusterRole 3 | metadata: 4 | name: fluentd-es 5 | rules: 6 | - apiGroups: 7 | - "" 8 | resources: 9 | - namespaces 10 | - pods 11 | verbs: 12 | - get 13 | - watch 14 | - list 15 | 16 | --- 17 | 18 | apiVersion: rbac.authorization.k8s.io/v1 19 | kind: ClusterRoleBinding 20 | metadata: 21 | name: fluentd-es 22 | roleRef: 23 | apiGroup: rbac.authorization.k8s.io 24 | kind: ClusterRole 25 | name: fluentd-es 26 | subjects: 27 | - kind: ServiceAccount 28 | name: fluentd-es 29 | namespace: kubeplatform -------------------------------------------------------------------------------- /logging/fluentd/sa.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ServiceAccount 3 | metadata: 4 | name: fluentd-es -------------------------------------------------------------------------------- /logging/fluentd/system.conf: -------------------------------------------------------------------------------- 1 | 2 | root_dir /tmp/fluentd-buffers/ 3 | -------------------------------------------------------------------------------- /logging/fluentd/system.input.conf: -------------------------------------------------------------------------------- 1 | # Example: 2 | # 2015-12-21 23:17:22,066 [salt.state ][INFO ] Completed state [net.ipv4.ip_forward] at time 23:17:22.066081 3 | 4 | @id minion 5 | @type tail 6 | format /^(?