Files
poimen-memory/k8s/infra/databases/opensearch.yaml
T
rock 8fd41216dc
Build and Push / Test (push) Failing after 1m42s
Build and Push / Build and push image (push) Skipped
feat: OpenSearch JWT auth via Authentik OIDC
2026-08-28 13:21:54 -07:00

474 lines
12 KiB
YAML

---
# OpenSearch StatefulSet for lexical (BM25) search
# Deployed alongside pgvector for hybrid semantic+lexical search
# JWT realm configured for Authentik integration
apiVersion: v1
kind: Namespace
metadata:
name: poimen
labels:
pod-security.kubernetes.io/enforce: baseline
pod-security.kubernetes.io/audit: baseline
pod-security.kubernetes.io/warn: baseline
---
# OpenSearch Service (Headless for StatefulSet discovery)
apiVersion: v1
kind: Service
metadata:
name: opensearch
namespace: poimen
labels:
app.kubernetes.io/name: opensearch
spec:
clusterIP: None # Headless
selector:
app.kubernetes.io/name: opensearch
ports:
- name: http
port: 9200
targetPort: 9200
- name: transport
port: 9300
targetPort: 9300
---
# OpenSearch Service (Internal for queries from Memory Service)
apiVersion: v1
kind: Service
metadata:
name: opensearch-internal
namespace: poimen
labels:
app.kubernetes.io/name: opensearch
spec:
type: ClusterIP
selector:
app.kubernetes.io/name: opensearch
ports:
- name: http
port: 9200
targetPort: 9200
---
# ConfigMap: OpenSearch configuration with JWT realm
apiVersion: v1
kind: ConfigMap
metadata:
name: opensearch-config
namespace: poimen
data:
opensearch.yml: |
# Cluster settings
cluster.name: poimen-memory
node.name: ${HOSTNAME}
cluster.initial_master_nodes: opensearch-0
discovery.seed_hosts: opensearch-0.opensearch.poimen.svc.cluster.local
# Network
network.host: 0.0.0.0
http.port: 9200
transport.port: 9300
# Security Plugin (JWT/Authentik OIDC)
plugins.security.disabled: "false"
plugins.security.ssl.http.enabled: "false"
plugins.security.ssl.transport.enabled: "false"
# JWT Authentication Realm for Authentik
plugins.security.authcz.admin_dn:
- "CN=admin,OU=admin,O=admin,L=admin,ST=admin,C=admin"
plugins.security.authc.realms.jwt_realm.type: jwt
plugins.security.authc.realms.jwt_realm.order: 1
plugins.security.authc.realms.jwt_realm.http_enabled: true
plugins.security.authc.realms.jwt_realm.transport_enabled: false
plugins.security.authc.realms.jwt_realm.description: "JWT realm for Authentik OIDC"
plugins.security.authc.realms.jwt_realm.token_name: Authorization
plugins.security.authc.realms.jwt_realm.token_extractor: "Bearer "
plugins.security.authc.realms.jwt_realm.jwt_header: Authorization
plugins.security.authc.realms.jwt_realm.roles_key: roles
plugins.security.authc.realms.jwt_realm.subject_key: sub
plugins.security.authc.realms.jwt_realm.jwks_uri: "https://authentik.riotpiao.com/application/o/poimen-memory/jwks/"
plugins.security.authc.realms.jwt_realm.jwks_refresh_interval_ms: 3600000
plugins.security.authc.realms.jwt_realm.issuer: "https://authentik.riotpiao.com/application/o/poimen-memory/"
plugins.security.authc.realms.jwt_realm.enable_ssl_peer_hostname_verification: false
plugins.security.authc.realms.jwt_realm.skip_jwt_verification: false
plugins.security.authc.cache.enable: true
plugins.security.authc.backends.internal_authc_backend.type: intern
# Memory
indices.memory.index_buffer_size: 30%
log4j2.properties: |
status = warn
appender.console.type = Console
appender.console.name = console
appender.console.layout.type = PatternLayout
appender.console.layout.pattern = [%d{ISO8601}][%-5p][%-25c{1.}] %marker%m%n
rootLogger.level = info
rootLogger.appenderRef.console.ref = console
internal_users.yml: |
admin:
hash: "$2y$12$K/SpwjtB.wW8u3/52l.f2OPST9/PgBkqquzi.Oi8KfRMfsKkCq3GO"
reserved: true
backend_roles:
- "admin"
- "all_access"
roles_mapping.yml: |
all_access:
reserved: false
backend_roles:
- "*"
hosts:
- "*"
---
# StatefulSet: OpenSearch (2 replicas for HA cluster)
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: opensearch
namespace: poimen
labels:
app.kubernetes.io/name: opensearch
spec:
serviceName: opensearch
replicas: 1
selector:
matchLabels:
app.kubernetes.io/name: opensearch
template:
metadata:
labels:
app.kubernetes.io/name: opensearch
spec:
serviceAccountName: opensearch
hostNetwork: false
initContainers:
- name: sysctl
image: busybox:1.28
command:
- sysctl
- -w
- vm.max_map_count=262144
securityContext:
privileged: true
containers:
- name: opensearch
image: opensearchproject/opensearch:2.11.0
imagePullPolicy: IfNotPresent
ports:
- name: http
containerPort: 9200
- name: transport
containerPort: 9300
env:
- name: HOSTNAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: CLUSTER_NAME
value: "poimen-memory"
- name: OPENSEARCH_JAVA_OPTS
value: "-Xms1g -Xmx1g"
- name: DISABLE_SECURITY_PLUGIN
value: "false"
- name: OPENSEARCH_INITIAL_ADMIN_PASSWORD
valueFrom:
secretKeyRef:
name: opensearch-secrets
key: admin-password
# Volume mounts
volumeMounts:
- name: opensearch-data
mountPath: /usr/share/opensearch/data
- name: opensearch-config
mountPath: /usr/share/opensearch/config/opensearch.yml
subPath: opensearch.yml
- name: opensearch-config
mountPath: /usr/share/opensearch/plugins/opensearch-security/securityconfig/internal_users.yml
subPath: internal_users.yml
- name: opensearch-config
mountPath: /usr/share/opensearch/plugins/opensearch-security/securityconfig/roles_mapping.yml
subPath: roles_mapping.yml
- name: opensearch-logs
mountPath: /usr/share/opensearch/logs
# Resource limits
resources:
requests:
memory: "1Gi"
cpu: "500m"
limits:
memory: "2Gi"
cpu: "1000m"
# Liveness probe (skip auth via basic fallback)
livenessProbe:
httpGet:
path: /_cluster/health
port: 9200
httpHeaders:
- name: Authorization
value: Basic YWRtaW46YWRtaW4="
initialDelaySeconds: 60
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 3
# Readiness probe
readinessProbe:
httpGet:
path: /_cluster/health?local=true
port: 9200
httpHeaders:
- name: Authorization
value: Basic YWRtaW46YWRtaW4="
initialDelaySeconds: 30
periodSeconds: 5
timeoutSeconds: 3
failureThreshold: 2
# Security context
securityContext:
runAsUser: 1000
# Volumes
volumes:
- name: opensearch-config
configMap:
name: opensearch-config
- name: opensearch-logs
emptyDir: {}
# PVC template for data persistence
volumeClaimTemplates:
- metadata:
name: opensearch-data
spec:
accessModes:
- ReadWriteOnce
storageClassName: longhorn
resources:
requests:
storage: 30Gi
---
# ServiceAccount for OpenSearch
apiVersion: v1
kind: ServiceAccount
metadata:
name: opensearch
namespace: poimen
---
# NetworkPolicy: Only Memory Service can access OpenSearch
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: opensearch-access
namespace: poimen
spec:
podSelector:
matchLabels:
app.kubernetes.io/name: opensearch
policyTypes:
- Ingress
ingress:
- from:
- podSelector:
matchLabels:
app.kubernetes.io/name: poimen-memory
- podSelector:
matchLabels:
app.kubernetes.io/name: opensearch-dashboards
ports:
- protocol: TCP
port: 9200
---
# OpenSearch Dashboards: UI for monitoring, querying, and managing OpenSearch
apiVersion: v1
kind: Service
metadata:
name: opensearch-dashboards
namespace: poimen
labels:
app.kubernetes.io/name: opensearch-dashboards
spec:
type: ClusterIP
selector:
app.kubernetes.io/name: opensearch-dashboards
ports:
- name: http
port: 5601
targetPort: 5601
---
# ConfigMap: OpenSearch Dashboards configuration
apiVersion: v1
kind: ConfigMap
metadata:
name: opensearch-dashboards-config
namespace: poimen
data:
opensearch_dashboards.yml: |
# OpenSearch Dashboards configuration
server.name: opensearch-dashboards
server.host: "0.0.0.0"
server.port: 5601
# OpenSearch connection
opensearch.hosts: ["http://opensearch-internal.poimen.svc.cluster.local:9200"]
opensearch.username: "admin"
opensearch.password: "admin"
opensearch.ssl.verificationMode: none
# Logging
logging.appenders.default.type: console
logging.appenders.default.layout.type: pattern
logging.appenders.default.layout.pattern: "[%date][%level][%logger] %message"
logging.root.appenders: [default]
logging.root.level: info
---
# Deployment: OpenSearch Dashboards
apiVersion: apps/v1
kind: Deployment
metadata:
name: opensearch-dashboards
namespace: poimen
labels:
app.kubernetes.io/name: opensearch-dashboards
spec:
replicas: 1
selector:
matchLabels:
app.kubernetes.io/name: opensearch-dashboards
template:
metadata:
labels:
app.kubernetes.io/name: opensearch-dashboards
spec:
serviceAccountName: opensearch-dashboards
containers:
- name: opensearch-dashboards
image: opensearchproject/opensearch-dashboards:2.11.0
imagePullPolicy: IfNotPresent
ports:
- name: http
containerPort: 5601
env:
- name: OPENSEARCH_HOSTS
value: "http://opensearch-internal.poimen.svc.cluster.local:9200"
- name: OPENSEARCH_USERNAME
value: "admin"
- name: OPENSEARCH_PASSWORD
valueFrom:
secretKeyRef:
name: opensearch-dashboards-secret
key: password
# Volume mounts
volumeMounts:
- name: opensearch-dashboards-config
mountPath: /usr/share/opensearch-dashboards/config/opensearch_dashboards.yml
subPath: opensearch_dashboards.yml
# Resource limits
resources:
requests:
memory: "256Mi"
cpu: "100m"
limits:
memory: "512Mi"
cpu: "500m"
# Liveness probe
livenessProbe:
httpGet:
path: /
port: 5601
initialDelaySeconds: 30
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 3
# Readiness probe
readinessProbe:
httpGet:
path: /
port: 5601
initialDelaySeconds: 15
periodSeconds: 5
timeoutSeconds: 3
failureThreshold: 2
# Security context
securityContext:
runAsNonRoot: true
runAsUser: 1000
capabilities:
drop:
- ALL
# Volumes
volumes:
- name: opensearch-dashboards-config
configMap:
name: opensearch-dashboards-config
---
# Secret: OpenSearch Dashboards password
apiVersion: v1
kind: Secret
metadata:
name: opensearch-dashboards-secret
namespace: poimen
type: Opaque
stringData:
password: "admin" # ⚠️ Change in production
---
# ServiceAccount for OpenSearch Dashboards
apiVersion: v1
kind: ServiceAccount
metadata:
name: opensearch-dashboards
namespace: poimen
---
# Secret for OpenSearch Admin Password
apiVersion: v1
kind: Secret
metadata:
name: opensearch-secrets
namespace: poimen
type: Opaque
stringData:
admin-password: "OpenSearch@Admin123!"