Skip to content

Instantly share code, notes, and snippets.

@jorritfolmer
Created November 30, 2025 11:19
Show Gist options
  • Select an option

  • Save jorritfolmer/7d559b376d23d2b737eb0d1aca7f711d to your computer and use it in GitHub Desktop.

Select an option

Save jorritfolmer/7d559b376d23d2b737eb0d1aca7f711d to your computer and use it in GitHub Desktop.
Running a lab with Elasticsearch, Kibana, Fleet and Elastic Package Registry containers

0. Prep container host

This HOWTO assumes Red Hat Enterprise Linux 9.x or 10.x with Podman. Even though this is a lab, the assumptions are that the skeleton could be scaled to something in production without major reconstructions, hence the reason for the elaborate TLS incantations that could easily be replaced by requesting certificates to be signed by another Root CA.

Download containers

podman pull docker.elastic.co/elastic-agent/elastic-agent:9.2.0
podman pull docker.elastic.co/kibana/kibana:9.2.0
podman pull docker.elastic.co/elasticsearch/elasticsearch:9.2.0

Create a separate network

podman network create elastic

Tune kernel for Elasticsearch

cat << EOF > /etc/sysctl.d/02-elastic.conf
vm.max_map_count = 262144
vm.swappiness = 1
EOF

sysctl --system --load

Create directory structure for container certificates and config

mkdir -p /var/elastic
chcon -R system_u:object_r:container_file_t:s0 /var/elastic
cd /var/elastic

1. Certificates

  1. Create a self-signed Root CA

    openssl genrsa -out ca.key 2048
    openssl req -x509 -new -nodes -key ca.key -sha256 -days $((10*365)) -extensions v3_ca -out ca.crt \
    -subj "/C=NL/ST=Fork Fountain/L=Numerous Dahlia/O=Zippy Mice/OU=SOC/CN=ROOT CA 2025"
    
  2. Create a key, CSR and certificate for Elasticsearch

    openssl genrsa -out elastic.key 2048
    openssl req -new -key elastic.key -out elastic.csr \
    -subj "/C=NL/ST=Fork Fountain/L=Numerous Dahlia/O=Zippy Mice/OU=SOC/CN=elastic" \
    -addext "subjectAltName=DNS:elastic.zippymice.internal"
    openssl x509 -req -in elastic.csr -CA ca.crt -CAkey ca.key -CAcreateserial \
    -out elastic.crt -days $((5*365)) -sha256 -copy_extensions=copyall
    
  3. Create a key, CSR and certificate for Fleet

    openssl genrsa -out fleet.key 2048
    openssl req -new -key fleet.key -out fleet.csr \
    -subj "/C=NL/ST=Fork Fountain/L=Numerous Dahlia/O=Zippy Mice/OU=SOC/CN=fleet" \
    -addext "subjectAltName=DNS:fleet.zippymice.internal"
    openssl x509 -req -in fleet.csr -CA ca.crt -CAkey ca.key -CAcreateserial \
    -out fleet.crt -days $((5*365)) -sha256 -copy_extensions=copyall
    
  4. Create a key, CSR and certificate for Kibana

    openssl genrsa -out kibana.key 2048
    openssl req -new -key kibana.key -out kibana.csr \
    -subj "/C=NL/ST=Fork Fountain/L=Numerous Dahlia/O=Zippy Mice/OU=SOC/CN=kibana" \
    -addext "subjectAltName=DNS:kibana.zippymice.internal" 
    openssl x509 -req -in kibana.csr -CA ca.crt -CAkey ca.key -CAcreateserial \
    -out kibana.crt -days $((5*365)) -sha256 -copy_extensions=copyall
    
  5. Move certificates into place

    mkdir /var/elastic/certs-elastic
    cp ca.crt /var/elastic/certs-elastic
    mv elastic.key /var/elastic/certs-elastic
    cat elastic.crt ca.crt > /var/elastic/certs-elastic/elastic.crt
    rm -f elastic.crt
    chmod 755 /var/elastic/certs-elastic
    chmod 644 /var/elastic/certs-elastic/*
    
    mkdir /var/elastic/data-elastic
    chmod 750 /var/elastic/data-elastic
    chown 1000:0 /var/elastic/data-elastic
    
    mkdir /var/elastic/certs-kibana
    cp ca.crt /var/elastic/certs-kibana
    mv kibana.key /var/elastic/certs-kibana
    cat kibana.crt ca.crt > /var/elastic/certs-kibana/kibana.crt
    rm -f kibana.crt
    chmod 755 /var/elastic/certs-kibana
    chmod 644 /var/elastic/certs-kibana/*
    
    mkdir /var/elastic/certs-fleet
    cp ca.crt /var/elastic/certs-fleet
    mv fleet.key /var/elastic/certs-fleet
    cat fleet.crt ca.crt > /var/elastic/certs-fleet/fleet.crt
    rm -f fleet.crt
    chmod 755 /var/elastic/certs-fleet
    chmod 644 /var/elastic/certs-fleet/*
    

2. Elasticsearch container

Create the Elasticsearch config file.

cat << EOF > /var/elastic/elastic.yml
xpack.security.enabled: true
network.host: 0.0.0.0

xpack.security:
  http.ssl:
    enabled: true
    key: /usr/share/elasticsearch/config/certificates/elastic.key
    certificate_authorities: /usr/share/elasticsearch/config/certificates/ca.crt
    certificate: /usr/share/elasticsearch/config/certificates/elastic.crt
    verification_mode: certificate
  transport.ssl:
    enabled: true
    key: /usr/share/elasticsearch/config/certificates/elastic.key
    certificate: /usr/share/elasticsearch/config/certificates/elastic.crt
    certificate_authorities: /usr/share/elasticsearch/config/certificates/ca.crt
    verification_mode: certificate

node.name: elastic

cluster:
  initial_master_nodes: elastic
  name: VJH
  routing.allocation.disk.watermark:
    low: 90%
    high: 95%
EOF

chmod 644 /var/elastic/elastic.yml
chown 1000:0 /var/elastic/elastic.yml

Generate a service token so Kibana can use it so access Elasticsearch. (Copy it for use in the later Kibana step)

podman run -d --name tmp1 docker.elastic.co/elasticsearch/elasticsearch:9.2.0
podman exec tmp1 bin/elasticsearch-service-tokens create elastic/kibana kibana-service-token
podman exec tmp1 cat config/service_tokens >service_tokens
podman stop tmp1
podman rm tmp1
chmod 644 service_tokens

Start the Elasticsearch container

podman run --detach --name elastic --hostname elastic \
-p 9200:9200 \
-p 9300:9300 \
--net=elastic \
--memory=16GB \
--cpus=2 \
--detach-keys=p,q \
-v "/var/elastic/data-elastic:/usr/share/elasticsearch/data" \
-v "/var/elastic/elastic.yml:/usr/share/elasticsearch/config/elasticsearch.yml:ro" \
-v "/var/elastic/service_tokens:/usr/share/elasticsearch/config/service_tokens" \
-v "/var/elastic/certs-elastic:/usr/share/elasticsearch/config/certificates:ro" \
docker.elastic.co/elasticsearch/elasticsearch:9.2.0

Open the Elasticsearch port in the local firewall

firewall-cmd --add-port=9200/tcp --permanent
firewall-cmd --reload

Reset the password for the elastic admin user if you don't want to hunt for it in the logs

podman exec -it elastic bin/elasticsearch-reset-password -u elastic

3. Kibana container

Create the Kibana config and remember to paste the service token you generated earlier into it.

cat << EOF > /var/elastic/kibana.yml
elasticsearch:
  hosts: https://elastic:9200
  ssl.certificateAuthorities: /usr/share/kibana/config/certificates/ca.crt
  serviceAccountToken: PASTE_SERVICE_TOKEN_FROM_PREVIOUS_STEP_HERE

server:
  publicBaseUrl: https://kibana:5601
  host: 0.0.0.0
  ssl.enabled: true
  ssl.certificate: /usr/share/kibana/config/certificates/kibana.crt
  ssl.key: /usr/share/kibana/config/certificates/kibana.key
  ssl.certificateAuthorities: /usr/share/kibana/config/certificates/ca.crt

telemetry.optIn: false
newsfeed.enabled: false

xpack:
  fleet.isAirGapped: true
  encryptedSavedObjects.encryptionKey: replace-with-a-minimum-32-byte-long-encryption-key
  security.encryptionKey: replace-with-a-minimum-32-byte-long-encryption-key
  reporting.encryptionKey: replace-with-a-minimum-32-byte-long-encryption-key
EOF

chmod 644 kibana.yml

Open the Kibana port in the host firewall

firewall-cmd --add-port=5601/tcp --permanent
firewall-cmd --reload
firewall-cmd --list-all

Start the Kibana container

podman run --detach --name kibana --hostname kibana \
-p 5601:5601 \
--net=elastic \
--memory=4GB \
--cpus=1 \
--detach-keys=p,q \
-v "/var/elastic/kibana.yml:/usr/share/kibana/config/kibana.yml:ro" \
-v "/var/elastic/certs-kibana:/usr/share/kibana/config/certificates:ro" \
docker.elastic.co/kibana/kibana:9.2.0

4. Fleet container

In Kibana -> Fleet -> Add Fleet Server -> Advanced (don't use Quick Start). Copy the Fleet Server service token into the command below.

podman run --detach --name fleet --hostname fleet \
-p 8220:8220 \
-v "/var/elastic/certs-fleet:/etc/fleet:ro" \
--env FLEET_URL=https://fleet:8220 \
--env FLEET_SERVER_ENABLE=true \
--env FLEET_SERVER_ELASTICSEARCH_HOST=https://elastic:9200 \
--env FLEET_SERVER_SERVICE_TOKEN=COPY_FLEET_SERVER_SERVICE_TOKEN_HERE \
--env FLEET_SERVER_POLICY_ID=fleet-server-policy \
--env FLEET_SERVER_PORT=8220 \
--env FLEET_CA=/etc/fleet/ca.crt \
--env FLEET_SERVER_ELASTICSEARCH_CA=/etc/fleet/ca.crt \
--env FLEET_SERVER_CERT=/etc/fleet/fleet.crt \
--env FLEET_SERVER_CERT_KEY=/etc/fleet/fleet.key \
docker.elastic.co/elastic-agent/elastic-agent:9.2.0

Open the Fleet port in the local host firewall:

firewall-cmd --add-port=8220/tcp --permanent
firewall-cmd --reload
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment