22359be40e
Close billing, tenancy, migration, build, and CI/CD gaps identified in the audit: wallet/gateway guards, full-UUID namespaces, idempotent migrations with base schema, stateful service stability, safer Dockerfiles/git builds, and platform chart hardening (Redis auth, RollingUpdate, backups, Swagger off). Co-authored-by: Cursor <cursoragent@cursor.com>
346 lines
8.5 KiB
YAML
346 lines
8.5 KiB
YAML
# Elasticsearch Production Deployment for CloudHost Platform
|
|
# Uses ECK (Elastic Cloud on Kubernetes) or direct Helm chart
|
|
|
|
# Namespace for all logging components
|
|
apiVersion: v1
|
|
kind: Namespace
|
|
metadata:
|
|
name: logging
|
|
labels:
|
|
app.kubernetes.io/managed-by: cloudhost
|
|
---
|
|
# Elasticsearch credentials — managed OUT-OF-BAND, never committed to git.
|
|
# Create the Secret before applying this manifest (or use a SealedSecret in
|
|
# the GitOps repo):
|
|
#
|
|
# kubectl -n logging create secret generic elasticsearch-credentials \
|
|
# --from-literal=ELASTIC_PASSWORD="$(openssl rand -base64 24)" \
|
|
# --from-literal=FLUENTBIT_PASSWORD="$(openssl rand -base64 24)"
|
|
#
|
|
# The backend reads the same values from ELASTIC_PASSWORD / FLUENTBIT_PASSWORD
|
|
# env vars (see cloudhost-platform values: backend.extraEnv or an extra Secret).
|
|
---
|
|
# ConfigMap for Elasticsearch configuration
|
|
apiVersion: v1
|
|
kind: ConfigMap
|
|
metadata:
|
|
name: elasticsearch-config
|
|
namespace: logging
|
|
data:
|
|
elasticsearch.yml: |
|
|
cluster.name: cloudhost-logs
|
|
network.host: 0.0.0.0
|
|
discovery.type: single-node
|
|
|
|
# Security settings
|
|
xpack.security.enabled: true
|
|
xpack.security.authc:
|
|
anonymous:
|
|
username: anonymous
|
|
roles:
|
|
authz_exception: true
|
|
|
|
# Disable unnecessary features to reduce resource usage
|
|
xpack.ml.enabled: false
|
|
xpack.graph.enabled: false
|
|
xpack.watcher.enabled: false
|
|
|
|
# Index settings
|
|
action.auto_create_index: true
|
|
|
|
# Roles for different users
|
|
roles.yml: |
|
|
# Admin role - full access
|
|
admin:
|
|
cluster:
|
|
- all
|
|
indices:
|
|
- names:
|
|
- '*'
|
|
privileges:
|
|
- all
|
|
|
|
# Fluent Bit writer role - can only write to logs-* indices
|
|
fluentbit_writer:
|
|
cluster:
|
|
- monitor
|
|
indices:
|
|
- names:
|
|
- 'logs-*'
|
|
privileges:
|
|
- create_index
|
|
- create
|
|
- index
|
|
- write
|
|
|
|
# User role template - read only their own indices
|
|
user_reader:
|
|
cluster:
|
|
- monitor
|
|
indices:
|
|
- names:
|
|
- 'logs-user-${user.metadata.user_id}-*'
|
|
privileges:
|
|
- read
|
|
- view_index_metadata
|
|
|
|
# Users file
|
|
users: |
|
|
elastic:$2a$10$rHvjZ5LzpRPRHJD1C9rZu.JZrGzMkVJ4.XRLjGQK1qMwKZO8RvkHO
|
|
fluentbit:$2a$10$zHvjZ5LzpRPRHJD1C9rZu.JZrGzMkVJ4.XRLjGQK1qMwKZO8RvkHO
|
|
|
|
users_roles: |
|
|
admin:elastic
|
|
fluentbit_writer:fluentbit
|
|
---
|
|
# PersistentVolumeClaim for Elasticsearch data
|
|
apiVersion: v1
|
|
kind: PersistentVolumeClaim
|
|
metadata:
|
|
name: elasticsearch-data
|
|
namespace: logging
|
|
spec:
|
|
accessModes:
|
|
- ReadWriteOnce
|
|
resources:
|
|
requests:
|
|
storage: 50Gi
|
|
# storageClassName: standard # Uncomment and set your storage class
|
|
---
|
|
# Elasticsearch StatefulSet
|
|
apiVersion: apps/v1
|
|
kind: StatefulSet
|
|
metadata:
|
|
name: elasticsearch
|
|
namespace: logging
|
|
labels:
|
|
app: elasticsearch
|
|
spec:
|
|
serviceName: elasticsearch
|
|
replicas: 1
|
|
selector:
|
|
matchLabels:
|
|
app: elasticsearch
|
|
template:
|
|
metadata:
|
|
labels:
|
|
app: elasticsearch
|
|
spec:
|
|
securityContext:
|
|
fsGroup: 1000
|
|
initContainers:
|
|
- name: fix-permissions
|
|
image: busybox:1.36
|
|
command: ['sh', '-c', 'chown -R 1000:1000 /usr/share/elasticsearch/data']
|
|
securityContext:
|
|
runAsUser: 0
|
|
privileged: true
|
|
volumeMounts:
|
|
- name: data
|
|
mountPath: /usr/share/elasticsearch/data
|
|
- name: increase-vm-max-map
|
|
image: busybox:1.36
|
|
command: ['sysctl', '-w', 'vm.max_map_count=262144']
|
|
securityContext:
|
|
privileged: true
|
|
- name: increase-fd-ulimit
|
|
image: busybox:1.36
|
|
command: ['sh', '-c', 'ulimit -n 65536']
|
|
securityContext:
|
|
privileged: true
|
|
containers:
|
|
- name: elasticsearch
|
|
image: docker.elastic.co/elasticsearch/elasticsearch:8.12.0
|
|
ports:
|
|
- containerPort: 9200
|
|
name: http
|
|
- containerPort: 9300
|
|
name: transport
|
|
env:
|
|
- name: ELASTIC_PASSWORD
|
|
valueFrom:
|
|
secretKeyRef:
|
|
name: elasticsearch-credentials
|
|
key: ELASTIC_PASSWORD
|
|
- name: discovery.type
|
|
value: single-node
|
|
- name: xpack.security.enabled
|
|
value: "true"
|
|
- name: ES_JAVA_OPTS
|
|
value: "-Xms1g -Xmx1g"
|
|
- name: bootstrap.memory_lock
|
|
value: "false"
|
|
resources:
|
|
requests:
|
|
cpu: 500m
|
|
memory: 2Gi
|
|
limits:
|
|
cpu: 2000m
|
|
memory: 4Gi
|
|
volumeMounts:
|
|
- name: data
|
|
mountPath: /usr/share/elasticsearch/data
|
|
readinessProbe:
|
|
httpGet:
|
|
path: /_cluster/health?local=true
|
|
port: 9200
|
|
scheme: HTTP
|
|
httpHeaders:
|
|
- name: Authorization
|
|
value: "Basic ZWxhc3RpYzpDbG91ZEhvc3QyMDI0IVNlY3VyZQ=="
|
|
initialDelaySeconds: 30
|
|
periodSeconds: 10
|
|
timeoutSeconds: 5
|
|
livenessProbe:
|
|
httpGet:
|
|
path: /_cluster/health?local=true
|
|
port: 9200
|
|
scheme: HTTP
|
|
httpHeaders:
|
|
- name: Authorization
|
|
value: "Basic ZWxhc3RpYzpDbG91ZEhvc3QyMDI0IVNlY3VyZQ=="
|
|
initialDelaySeconds: 60
|
|
periodSeconds: 30
|
|
timeoutSeconds: 10
|
|
volumes:
|
|
- name: data
|
|
persistentVolumeClaim:
|
|
claimName: elasticsearch-data
|
|
---
|
|
# Elasticsearch Service
|
|
apiVersion: v1
|
|
kind: Service
|
|
metadata:
|
|
name: elasticsearch
|
|
namespace: logging
|
|
labels:
|
|
app: elasticsearch
|
|
spec:
|
|
type: ClusterIP
|
|
ports:
|
|
- port: 9200
|
|
targetPort: 9200
|
|
name: http
|
|
- port: 9300
|
|
targetPort: 9300
|
|
name: transport
|
|
selector:
|
|
app: elasticsearch
|
|
---
|
|
# Kibana Deployment
|
|
apiVersion: apps/v1
|
|
kind: Deployment
|
|
metadata:
|
|
name: kibana
|
|
namespace: logging
|
|
labels:
|
|
app: kibana
|
|
spec:
|
|
replicas: 1
|
|
selector:
|
|
matchLabels:
|
|
app: kibana
|
|
template:
|
|
metadata:
|
|
labels:
|
|
app: kibana
|
|
spec:
|
|
containers:
|
|
- name: kibana
|
|
image: docker.elastic.co/kibana/kibana:8.12.0
|
|
ports:
|
|
- containerPort: 5601
|
|
env:
|
|
- name: ELASTICSEARCH_HOSTS
|
|
value: "http://elasticsearch:9200"
|
|
- name: ELASTICSEARCH_USERNAME
|
|
value: "elastic"
|
|
- name: ELASTICSEARCH_PASSWORD
|
|
valueFrom:
|
|
secretKeyRef:
|
|
name: elasticsearch-credentials
|
|
key: ELASTIC_PASSWORD
|
|
- name: SERVER_NAME
|
|
value: "kibana"
|
|
- name: XPACK_SECURITY_ENABLED
|
|
value: "true"
|
|
resources:
|
|
requests:
|
|
cpu: 200m
|
|
memory: 512Mi
|
|
limits:
|
|
cpu: 1000m
|
|
memory: 1Gi
|
|
readinessProbe:
|
|
httpGet:
|
|
path: /api/status
|
|
port: 5601
|
|
initialDelaySeconds: 30
|
|
periodSeconds: 10
|
|
livenessProbe:
|
|
httpGet:
|
|
path: /api/status
|
|
port: 5601
|
|
initialDelaySeconds: 60
|
|
periodSeconds: 30
|
|
---
|
|
# Kibana Service
|
|
apiVersion: v1
|
|
kind: Service
|
|
metadata:
|
|
name: kibana
|
|
namespace: logging
|
|
labels:
|
|
app: kibana
|
|
spec:
|
|
type: ClusterIP
|
|
ports:
|
|
- port: 5601
|
|
targetPort: 5601
|
|
selector:
|
|
app: kibana
|
|
---
|
|
# Index Lifecycle Management Policy
|
|
apiVersion: v1
|
|
kind: ConfigMap
|
|
metadata:
|
|
name: elasticsearch-ilm-policy
|
|
namespace: logging
|
|
data:
|
|
ilm-policy.json: |
|
|
{
|
|
"policy": {
|
|
"phases": {
|
|
"hot": {
|
|
"min_age": "0ms",
|
|
"actions": {
|
|
"rollover": {
|
|
"max_age": "7d",
|
|
"max_size": "5gb"
|
|
},
|
|
"set_priority": {
|
|
"priority": 100
|
|
}
|
|
}
|
|
},
|
|
"warm": {
|
|
"min_age": "7d",
|
|
"actions": {
|
|
"set_priority": {
|
|
"priority": 50
|
|
},
|
|
"shrink": {
|
|
"number_of_shards": 1
|
|
}
|
|
}
|
|
},
|
|
"delete": {
|
|
"min_age": "30d",
|
|
"actions": {
|
|
"delete": {}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|