--- # OpenSearch Security Config apiVersion: v1 kind: ConfigMap metadata: name: opensearch-config namespace: poimen labels: app: opensearch data: opensearch.yml: | cluster.name: poimen-memory node.name: ${HOSTNAME} discovery.seed_hosts: "opensearch-0.opensearch,opensearch-1.opensearch" cluster.initial_master_nodes: "opensearch-0,opensearch-1" # Security Plugin Configuration plugins: security: ssl: transport: pemcert_filepath: certs/node.pem pemkey_filepath: certs/node-key.pem pemtrustedcas_filepath: certs/root-ca.pem enforce_hostname_verification: false http: enabled: true pemcert_filepath: certs/node.pem pemkey_filepath: certs/node-key.pem pemtrustedcas_filepath: certs/root-ca.pem # JWT Authentication Realm authcz: admin_dn: - CN=admin,OU=admin,O=admin,L=admin,ST=admin,C=admin authc: realms: jwt_realm: type: jwt order: 1 http_enabled: true transport_enabled: false description: "JWT realm for Authentik integration" # Token location and format token_name: Authorization token_extractor: "Bearer " # Extract token after "Bearer " # JWT signing configuration jwt_header: "Authorization" jwt_url_parameter: null roles_key: "roles" subject_key: "sub" # JWKS endpoint from Authentik jwks_uri: "https://authentik.riotpiao.com/application/o/poimen-memory/jwks/" jwks_refresh_interval_ms: 3600000 # 1 hour # Issuer validation issuer: "https://authentik.riotpiao.com/application/o/poimen-memory/" audience: null # Claims mapping enable_ssl_peer_hostname_verification: false skip_jwt_verification: false backends: internal_authc_backend: type: intern # Role-based access control roles_mapping: all_access: - "*" own_index: - "?kibana" - "?opensearch-dashboards" logstash: - "logstash" # Index-level permissions roles: all_access: cluster_permissions: - "*" index_permissions: - index_patterns: - "*" allowed_actions: - "*" tenant_permissions: - tenant_patterns: - "*" allowed_actions: - "*" read_vault: cluster_permissions: - cluster:monitor/health - indices:data/read/search index_permissions: - index_patterns: - "vault-*" allowed_actions: - "indices:data/read/search" - "indices:data/read/get" tenant_permissions: - tenant_patterns: - "global_tenant" allowed_actions: - "kibana_all_read" write_vault: cluster_permissions: - cluster:monitor/health - indices:data/write/index - indices:data/write/update index_permissions: - index_patterns: - "vault-*" allowed_actions: - "indices:data/write/index" - "indices:data/write/update" - "indices:data/read/search" tenant_permissions: - tenant_patterns: - "global_tenant" allowed_actions: - "kibana_all" # Map JWT claims to OpenSearch internal users authc_cache_enable: true internal_users.yml: | # Internal admin user (for bootstrapping) admin: hash: "$2y$12$K/SpwjtB.wW8u3/52l.f2OPST9/PgBkqquzi.Oi8KfRMfsKkCq3GO" # admin:admin123 reserved: true backend_roles: - "admin" - "all_access" attributes: attribute1: "value1" attribute2: "value2" attribute3: "value3" roles_mapping.yml: | all_access: reserved: false users: - "admin" backend_roles: - "*" hosts: - "*" action_groups.yml: | # Add standard action groups here --- # OpenSearch StatefulSet apiVersion: apps/v1 kind: StatefulSet metadata: name: opensearch namespace: poimen labels: app: opensearch spec: serviceName: opensearch replicas: 2 selector: matchLabels: app: opensearch template: metadata: labels: app: opensearch spec: affinity: podAntiAffinity: preferredDuringSchedulingIgnoredDuringExecution: - weight: 100 podAffinityTerm: labelSelector: matchExpressions: - key: app operator: In values: - opensearch topologyKey: kubernetes.io/hostname initContainers: - name: fix-permissions image: busybox:1.28 command: - sysctl - -w - vm.max_map_count=262144 securityContext: privileged: true containers: - name: opensearch image: opensearchproject/opensearch:2.11.0 env: - name: OPENSEARCH_JAVA_OPTS value: "-Xms2g -Xmx2g -XX:+AlwaysPreTouch -XX:+UseG1GC -XX:MaxGCPauseMillis=30" - name: OPENSEARCH_INITIAL_ADMIN_PASSWORD valueFrom: secretKeyRef: name: opensearch-secrets key: admin-password - name: DISABLE_SECURITY_PLUGIN value: "false" - name: OPENSEARCH_SECURITY_SSL_HTTP_ENABLED value: "true" ports: - containerPort: 9200 name: http protocol: TCP - containerPort: 9300 name: node-comm protocol: TCP resources: requests: memory: "2Gi" cpu: "500m" limits: memory: "4Gi" cpu: "1000m" livenessProbe: httpGet: path: /_cluster/health port: 9200 scheme: HTTPS initialDelaySeconds: 30 periodSeconds: 10 timeoutSeconds: 5 failureThreshold: 3 readinessProbe: httpGet: path: /_cluster/health port: 9200 scheme: HTTPS initialDelaySeconds: 10 periodSeconds: 5 timeoutSeconds: 5 failureThreshold: 3 volumeMounts: - name: data mountPath: /usr/share/opensearch/data - name: config mountPath: /usr/share/opensearch/config/opensearch.yml subPath: opensearch.yml - name: config mountPath: /usr/share/opensearch/plugins/opensearch-security/securityconfig/internal_users.yml subPath: internal_users.yml - name: config mountPath: /usr/share/opensearch/plugins/opensearch-security/securityconfig/roles_mapping.yml subPath: roles_mapping.yml - name: config mountPath: /usr/share/opensearch/plugins/opensearch-security/securityconfig/action_groups.yml subPath: action_groups.yml volumes: - name: config configMap: name: opensearch-config volumeClaimTemplates: - metadata: name: data spec: accessModes: - ReadWriteOnce storageClassName: longhorn resources: requests: storage: 30Gi --- # OpenSearch Service (Headless for StatefulSet) apiVersion: v1 kind: Service metadata: name: opensearch namespace: poimen labels: app: opensearch spec: clusterIP: None # Headless service selector: app: opensearch ports: - port: 9200 targetPort: 9200 protocol: TCP name: http - port: 9300 targetPort: 9300 protocol: TCP name: node-comm publishNotReadyAddresses: true --- # OpenSearch Internal Service (for direct access) apiVersion: v1 kind: Service metadata: name: opensearch-internal namespace: poimen labels: app: opensearch spec: type: ClusterIP selector: app: opensearch ports: - port: 9200 targetPort: 9200 protocol: TCP name: http --- # Secret for OpenSearch Admin Password apiVersion: v1 kind: Secret metadata: name: opensearch-secrets namespace: poimen type: Opaque stringData: admin-password: "OpenSearch@Admin123!" # TODO: Change to secure password --- # NetworkPolicy: Only Memory Service can access OpenSearch apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: opensearch-access namespace: poimen spec: podSelector: matchLabels: app: opensearch policyTypes: - Ingress ingress: - from: - podSelector: matchLabels: app.kubernetes.io/name: poimen-memory ports: - protocol: TCP port: 9200 --- # NetworkPolicy: OpenSearch can communicate internally apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: opensearch-internal-comm namespace: poimen spec: podSelector: matchLabels: app: opensearch policyTypes: - Ingress ingress: - from: - podSelector: matchLabels: app: opensearch ports: - protocol: TCP port: 9300