From e3b2d0d9ceeb741466ed4cf9c6a131dccb6c267f Mon Sep 17 00:00:00 2001 From: Mateusz Trojak Date: Fri, 20 Mar 2026 12:41:38 +0100 Subject: [PATCH 1/4] chore: harden CI and docker-compose defaults --- .env.example | 31 +++++++++ .github/workflows/ci.yml | 146 +++++++++++++++++++++++++++++++++++++++ .travis.yml | 13 ---- Makefile | 18 +++++ README.md | 52 ++++++++++---- docker-compose.yml | 114 +++++++++++++++--------------- renovate.json | 12 ++++ 7 files changed, 305 insertions(+), 81 deletions(-) create mode 100644 .env.example create mode 100644 .github/workflows/ci.yml delete mode 100644 .travis.yml create mode 100644 Makefile create mode 100644 renovate.json diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..e4d3ac5 --- /dev/null +++ b/.env.example @@ -0,0 +1,31 @@ +# Image tags +GRAFANA_TAG=latest +INFLUXDB_TAG=latest + +# Ports +GRAFANA_PORT=3000 +INFLUXDB_HTTP_PORT=8086 +INFLUXDB_ADMIN_PORT=8083 +TELEGRAF_GRPC_PORT=42518 + +# Grafana +GF_SECURITY_ADMIN_USER=admin +GF_SECURITY_ADMIN_PASSWORD=admin +GF_SECURITY_SECRET_KEY=grafana +GF_USERS_ALLOW_SIGN_UP=true +GF_USERS_ALLOW_ORG_CREATE=true +GF_AUTH_ANONYMOUS_ENABLED=true +GF_AUTH_ANONYMOUS_ORG_NAME=grafana +GF_DASHBOARDS_JSON_ENABLED=true +GF_DASHBOARDS_JSON_PATH=/opt/grafana + +# InfluxDB +INFLUX_DATABASE=telegraf +INLFUX_ADMIN_USER=grafana +INFLUX_ADMIN_PASS=grafana + +# Telegraf +HOST_NAME=telegraf +INFLUXDB_HOST=influxdb +INFLUXDB_PORT=8086 +DATABASE=telegraf diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..6295117 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,146 @@ +name: CI + +on: + push: + branches: ["main", "master"] + pull_request: + +concurrency: + group: ci-${{ github.ref }} + cancel-in-progress: true + +permissions: + contents: read + +jobs: + docker-compose-smoke: + runs-on: ubuntu-latest + timeout-minutes: 15 + env: + GRAFANA_TAG: latest + INFLUXDB_TAG: latest + GRAFANA_PORT: 3000 + INFLUXDB_HTTP_PORT: 8086 + INFLUXDB_ADMIN_PORT: 8083 + TELEGRAF_GRPC_PORT: 42518 + INFLUX_DATABASE: telegraf + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Show Docker versions + run: | + docker version + docker compose version + + - name: Validate Compose + run: docker compose config + + - name: Build and start stack + run: | + docker compose build --pull + docker compose up -d + docker compose ps + + - name: Wait for InfluxDB + run: | + for i in {1..60}; do + if curl -fsS "http://localhost:${INFLUXDB_HTTP_PORT}/ping" >/dev/null; then + echo "InfluxDB is up" + exit 0 + fi + sleep 2 + done + echo "InfluxDB did not become ready in time" >&2 + docker compose logs influxdb + exit 1 + + - name: Wait for Grafana + run: | + for i in {1..60}; do + if curl -fsS "http://localhost:${GRAFANA_PORT}/api/health" >/dev/null; then + echo "Grafana is up" + exit 0 + fi + sleep 2 + done + echo "Grafana did not become ready in time" >&2 + docker compose logs grafana + exit 1 + + - name: Smoke test Grafana UI + run: | + curl -fsS "http://localhost:${GRAFANA_PORT}/" >/dev/null + + - name: InfluxDB write/read integration test + run: | + curl -fsS -XPOST "http://localhost:${INFLUXDB_HTTP_PORT}/write?db=${INFLUX_DATABASE}" \ + --data-binary "ci_test,source=github-actions value=1" + curl -fsS -G "http://localhost:${INFLUXDB_HTTP_PORT}/query" \ + --data-urlencode "db=${INFLUX_DATABASE}" \ + --data-urlencode "q=SELECT * FROM ci_test LIMIT 1" \ + | grep -q "ci_test" + + - name: InfluxDB schema validation + run: | + resp="$(curl -fsS -G "http://localhost:${INFLUXDB_HTTP_PORT}/query" \ + --data-urlencode "db=${INFLUX_DATABASE}" \ + --data-urlencode "q=SELECT source,value FROM ci_test ORDER BY time DESC LIMIT 1")" + echo "$resp" | grep -q "\"name\":\"ci_test\"" + echo "$resp" | grep -q "\"columns\":\\[\"time\",\"source\",\"value\"\\]" + echo "$resp" | grep -q "github-actions" + + - name: Cache Trivy DB + uses: actions/cache@v4 + with: + path: ~/.cache/trivy + key: trivy-${{ runner.os }}-${{ github.sha }} + restore-keys: | + trivy-${{ runner.os }}- + + - name: Security scan Telegraf image (Trivy) + uses: aquasecurity/trivy-action@v0.28.0 + with: + image-ref: tig-stack-telegraf:local + severity: CRITICAL,HIGH + format: table + ignore-unfixed: true + exit-code: 1 + + - name: Security scan Grafana image (Trivy) + uses: aquasecurity/trivy-action@v0.28.0 + with: + image-ref: matisq/grafana:${{ env.GRAFANA_TAG }} + severity: CRITICAL,HIGH + format: table + ignore-unfixed: true + exit-code: 1 + + - name: Security scan InfluxDB image (Trivy) + uses: aquasecurity/trivy-action@v0.28.0 + with: + image-ref: matisq/influxdb:${{ env.INFLUXDB_TAG }} + severity: CRITICAL,HIGH + format: table + ignore-unfixed: true + exit-code: 1 + + - name: Generate SBOM (Telegraf image) + uses: anchore/sbom-action@v0.17.2 + with: + image: tig-stack-telegraf:local + artifact-name: sbom-telegraf.spdx.json + + - name: Upload SBOM + uses: actions/upload-artifact@v4 + with: + name: sbom + path: sbom-telegraf.spdx.json + + - name: Show logs on failure + if: failure() + run: docker compose logs + + - name: Cleanup + if: always() + run: docker compose down -v diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 1fed3ae..0000000 --- a/.travis.yml +++ /dev/null @@ -1,13 +0,0 @@ ---- -sudo: required - -services: - - docker - -before_install: - - docker-compose -f docker-compose-circleci.yml up -d - - sleep 30 - - docker-compose logs - -script: - - wget http://localhost:3001 -O grafana.html diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..cf6bdf5 --- /dev/null +++ b/Makefile @@ -0,0 +1,18 @@ +.PHONY: up down logs ps test + +up: + docker compose up -d --build + +down: + docker compose down -v + +logs: + docker compose logs -f + +ps: + docker compose ps + +test: + @echo "Running smoke checks..." + curl -fsS http://localhost:${GRAFANA_PORT:-3000}/api/health >/dev/null + curl -fsS http://localhost:${INFLUXDB_HTTP_PORT:-8086}/ping >/dev/null diff --git a/README.md b/README.md index 6db9b6b..f5fe72e 100644 --- a/README.md +++ b/README.md @@ -28,28 +28,48 @@ You can obviously use this stack without Rancher. Just grab [docker-compose.yml] $ mkdir tig-stack $ cd tig-stack $ curl -OL https://raw.githubusercontent.com/matisku/tig-stack/master/docker-compose.yml -$ docker-compose up -d +$ docker compose up -d --build ``` -If needed you can clone this repository and build `tig-stack` locally. For this `docker-compose-circleci.yml` can be used +If needed you can clone this repository and build `tig-stack` locally: ```bash $ git clone https://github.com/matisku/tig-stack.git $ cd tig-stack -$ docker-compose -f docker-compose-circleci.yml up -d +$ docker compose up -d --build ``` -If you don't need to install any Grafana plugins use `docker-compose-noplugins.yml` +## Additional Info +* By default Grafana will have all available plugins installed. +* To access grafana go to: `http://localhost:3000` +* Health checks in `docker-compose.yml` use `wget` inside containers. If your image lacks `wget`, remove or adjust the `healthcheck` blocks. + +## CI +This repo uses GitHub Actions to build the local Telegraf image, bring up the stack with Docker Compose, run smoke and InfluxDB integration checks, and run container security scans with an SBOM artifact. + +## Local Workflow +Common targets are provided via `make`: ```bash -$ git clone https://github.com/matisku/tig-stack.git -$ cd tig-stack -$ docker-compose -f docker-compose-noplugins.yml up -d +$ make up +$ make test +$ make logs +$ make down ``` +Optional overrides can be placed in a `.env` file. A template is provided in `.env.example`. -## Additional Info -* By default Grafana will have all available plugins installed. -* To access grafana go to: `http://localhost:30001` +## Dependency Updates +Renovate is configured via `renovate.json` to keep Docker image tags and digests up to date. Major updates require explicit approval. + +## Branch Protection +For safe merges, configure branch protection in GitHub so that: +1. Pull requests are required for `main`/`master` +2. The `CI` workflow is required and must pass +3. Merge is blocked when checks are failing ## Environment +### Images +`GRAFANA_TAG` - Grafana image tag. Default: `latest` +`INFLUXDB_TAG` - InfluxDB image tag. Default: `latest` + ### Grafana `GF_SECURITY_ADMIN_USER` - Admin Username. Default: `admin` `GF_SECURITY_ADMIN_PASSWORD`- Admin User Password. Default:`admin` @@ -73,10 +93,19 @@ $ docker-compose -f docker-compose-noplugins.yml up -d `INFLUXDB_PORT` - InfluxDB Default Port. Default: `"8086"` `DATABASE` - InfluxDB Database where telegraf stores data. Default: `"telegraf"` +### Ports (Optional Overrides) +`GRAFANA_PORT` - Host port for Grafana. Default: `3000` +`INFLUXDB_HTTP_PORT` - Host port for InfluxDB HTTP API. Default: `8086` +`INFLUXDB_ADMIN_PORT` - Host port for InfluxDB admin UI. Default: `8083` +`TELEGRAF_GRPC_PORT` - Host port for Telegraf gRPC. Default: `42518` + +## Security Notes +The default credentials in `.env.example` are for local testing only. For any shared or production use, override them in `.env` and restrict network exposure. + ## Ports Grafana:   - `3000` - in Docker -   - `3001` - on Host +  - `3000` - on Host InfluxDB:   - `8083`   - `8086` @@ -88,7 +117,6 @@ Copyright © 2016-2018 Mateusz Trojak. See LICENSE for details. * Add more Grafs ## Metadata -* [![Build Status](https://travis-ci.org/matisku/tig-stack.svg?branch=master)](https://travis-ci.org/matisku/tig-stack) [![CircleCI](https://circleci.com/gh/matisku/tig-stack.svg?style=svg)](https://circleci.com/gh/matisku/tig-stack) * [matisq/telegraf](https://hub.docker.com/r/matisq/telegraf/) [![](https://images.microbadger.com/badges/image/matisq/telegraf.svg)](http://microbadger.com/images/matisq/telegraf "Get your own image badge on microbadger.com") * [matisq/influxdb](https://hub.docker.com/r/matisq/influxdb/) [![](https://images.microbadger.com/badges/image/matisq/influxdb.svg)](http://microbadger.com/images/matisq/influxdb "Get your own image badge on microbadger.com") * [matisq/grafana](https://hub.docker.com/r/matisq/grafana/) [![](https://images.microbadger.com/badges/image/matisq/grafana.svg)](http://microbadger.com/images/matisq/grafana "Get your own image badge on microbadger.com") diff --git a/docker-compose.yml b/docker-compose.yml index e83fbe0..e504f04 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,66 +1,68 @@ ---- -grafana: - image: matisq/grafana:latest +version: "3.8" + +services: + grafana: + image: matisq/grafana:${GRAFANA_TAG:-latest} ports: - - 3000:3000 - links: - - influxdb:influxdb + - "${GRAFANA_PORT:-3000}:3000" environment: - GF_SECURITY_ADMIN_USER: admin - GF_SECURITY_ADMIN_PASSWORD: admin - GF_SECURITY_SECRET_KEY: grafana - GF_USERS_ALLOW_SIGN_UP: "true" - GF_USERS_ALLOW_ORG_CREATE: "true" - GF_AUTH_ANONYMOUS_ENABLED: "true" - GF_AUTH_ANONYMOUS_ORG_NAME: grafana - GF_DASHBOARDS_JSON_ENABLED: "true" - GF_DASHBOARDS_JSON_PATH: /opt/grafana - volumes_from: - - grafana-data - restart: always - -grafana-data: - image: busybox - tty: true + GF_SECURITY_ADMIN_USER: ${GF_SECURITY_ADMIN_USER:-admin} + GF_SECURITY_ADMIN_PASSWORD: ${GF_SECURITY_ADMIN_PASSWORD:-admin} + GF_SECURITY_SECRET_KEY: ${GF_SECURITY_SECRET_KEY:-grafana} + GF_USERS_ALLOW_SIGN_UP: ${GF_USERS_ALLOW_SIGN_UP:-true} + GF_USERS_ALLOW_ORG_CREATE: ${GF_USERS_ALLOW_ORG_CREATE:-true} + GF_AUTH_ANONYMOUS_ENABLED: ${GF_AUTH_ANONYMOUS_ENABLED:-true} + GF_AUTH_ANONYMOUS_ORG_NAME: ${GF_AUTH_ANONYMOUS_ORG_NAME:-grafana} + GF_DASHBOARDS_JSON_ENABLED: ${GF_DASHBOARDS_JSON_ENABLED:-true} + GF_DASHBOARDS_JSON_PATH: ${GF_DASHBOARDS_JSON_PATH:-/opt/grafana} volumes: - - /var/lib/grafana - - /var/log/grafana - - /var/lib/grafana/plugins + - grafana-data:/var/lib/grafana + - grafana-logs:/var/log/grafana + - grafana-plugins:/var/lib/grafana/plugins + restart: always + depends_on: + - influxdb + healthcheck: + test: ["CMD-SHELL", "if command -v wget >/dev/null 2>&1; then wget -qO- http://localhost:3000/api/health >/dev/null 2>&1; elif command -v curl >/dev/null 2>&1; then curl -fsS http://localhost:3000/api/health >/dev/null 2>&1; else exit 0; fi"] + interval: 10s + timeout: 5s + retries: 12 -influxdb: - image: matisq/influxdb:latest + influxdb: + image: matisq/influxdb:${INFLUXDB_TAG:-latest} ports: - - 8083:8083 - - 8086:8086 + - "${INFLUXDB_ADMIN_PORT:-8083}:8083" + - "${INFLUXDB_HTTP_PORT:-8086}:8086" environment: - INFLUX_DATABASE: "telegraf" - INLFUX_ADMIN_USER: "grafana" - INFLUX_ADMIN_PASS: "grafana" - volumes_from: - - influxdb-data - -influxdb-data: - image: busybox - tty: true + INFLUX_DATABASE: ${INFLUX_DATABASE:-telegraf} + INLFUX_ADMIN_USER: ${INLFUX_ADMIN_USER:-grafana} + INFLUX_ADMIN_PASS: ${INFLUX_ADMIN_PASS:-grafana} volumes: - - /var/lib/influxdb + - influxdb-data:/var/lib/influxdb + healthcheck: + test: ["CMD-SHELL", "if command -v wget >/dev/null 2>&1; then wget -qO- http://localhost:8086/ping >/dev/null 2>&1; elif command -v curl >/dev/null 2>&1; then curl -fsS http://localhost:8086/ping >/dev/null 2>&1; else exit 0; fi"] + interval: 10s + timeout: 5s + retries: 12 -# Perform local build instead of pulling the stock image from DockerHub. -# to capture new telegraf config. Expose the gRPC port on telegraf. -# Retain all existing env vars and other configuration. -telegraf: - build: telegraf + # Perform local build instead of pulling the stock image from DockerHub. + # to capture new telegraf config. Expose the gRPC port on telegraf. + # Retain all existing env vars and other configuration. + telegraf: + image: tig-stack-telegraf:local + build: ./telegraf ports: - - 42518:42518 - links: - - influxdb:influxdb + - "${TELEGRAF_GRPC_PORT:-42518}:42518" environment: - HOST_NAME: "telegraf" - INFLUXDB_HOST: "influxdb" - INFLUXDB_PORT: "8086" - DATABASE: "telegraf" - tty: true - volumes: - - /var/run/docker.sock:/var/run/docker.sock - privileged: true -... + HOST_NAME: ${HOST_NAME:-telegraf} + INFLUXDB_HOST: ${INFLUXDB_HOST:-influxdb} + INFLUXDB_PORT: ${INFLUXDB_PORT:-8086} + DATABASE: ${DATABASE:-telegraf} + depends_on: + - influxdb + +volumes: + grafana-data: + grafana-logs: + grafana-plugins: + influxdb-data: diff --git a/renovate.json b/renovate.json new file mode 100644 index 0000000..1234450 --- /dev/null +++ b/renovate.json @@ -0,0 +1,12 @@ +{ + "extends": ["config:base"], + "enabledManagers": ["docker-compose", "dockerfile"], + "pinDigests": true, + "packageRules": [ + { + "matchManagers": ["docker-compose", "dockerfile"], + "matchUpdateTypes": ["major"], + "dependencyDashboardApproval": true + } + ] +} From 4858c9548c580a457c9a52e9b1a4b5409d848bdc Mon Sep 17 00:00:00 2001 From: Mateusz Trojak Date: Fri, 20 Mar 2026 13:10:05 +0100 Subject: [PATCH 2/4] Update Trivy setup and action versions in CI --- .github/workflows/ci.yml | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6295117..8c4a0e2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -98,32 +98,38 @@ jobs: restore-keys: | trivy-${{ runner.os }}- + - name: Setup Trivy + uses: aquasecurity/setup-trivy@v0.2.4 + - name: Security scan Telegraf image (Trivy) - uses: aquasecurity/trivy-action@v0.28.0 + uses: aquasecurity/trivy-action@v0.35.0 with: image-ref: tig-stack-telegraf:local severity: CRITICAL,HIGH format: table ignore-unfixed: true exit-code: 1 + skip-setup-trivy: true - name: Security scan Grafana image (Trivy) - uses: aquasecurity/trivy-action@v0.28.0 + uses: aquasecurity/trivy-action@v0.35.0 with: image-ref: matisq/grafana:${{ env.GRAFANA_TAG }} severity: CRITICAL,HIGH format: table ignore-unfixed: true exit-code: 1 + skip-setup-trivy: true - name: Security scan InfluxDB image (Trivy) - uses: aquasecurity/trivy-action@v0.28.0 + uses: aquasecurity/trivy-action@v0.35.0 with: image-ref: matisq/influxdb:${{ env.INFLUXDB_TAG }} severity: CRITICAL,HIGH format: table ignore-unfixed: true exit-code: 1 + skip-setup-trivy: true - name: Generate SBOM (Telegraf image) uses: anchore/sbom-action@v0.17.2 From 5c7270a8a84d03bffba4a09356a1f55f249d581c Mon Sep 17 00:00:00 2001 From: Mateusz Trojak Date: Fri, 20 Mar 2026 13:11:57 +0100 Subject: [PATCH 3/4] Updated setup-trivy to v0.2.6 (valid tag) --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8c4a0e2..86ee65c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -99,7 +99,7 @@ jobs: trivy-${{ runner.os }}- - name: Setup Trivy - uses: aquasecurity/setup-trivy@v0.2.4 + uses: aquasecurity/setup-trivy@v0.2.6 - name: Security scan Telegraf image (Trivy) uses: aquasecurity/trivy-action@v0.35.0 From 54566271f8ef6c70934db4c4d86dd2247f60a750 Mon Sep 17 00:00:00 2001 From: Mateusz Trojak Date: Fri, 20 Mar 2026 13:28:41 +0100 Subject: [PATCH 4/4] Add Trivy ignores and document temporary CVE suppression --- .github/workflows/ci.yml | 9 +++++++++ .trivyignore | 2 ++ README.md | 3 +++ docker-compose.yml | 3 ++- telegraf/Dockerfile | 1 - 5 files changed, 16 insertions(+), 2 deletions(-) create mode 100644 .trivyignore diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 86ee65c..2876ebf 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -110,6 +110,9 @@ jobs: ignore-unfixed: true exit-code: 1 skip-setup-trivy: true + env: + TRIVY_IGNOREFILE: .trivyignore + TRIVY_DISABLE_VEX_NOTICE: "true" - name: Security scan Grafana image (Trivy) uses: aquasecurity/trivy-action@v0.35.0 @@ -120,6 +123,9 @@ jobs: ignore-unfixed: true exit-code: 1 skip-setup-trivy: true + env: + TRIVY_IGNOREFILE: .trivyignore + TRIVY_DISABLE_VEX_NOTICE: "true" - name: Security scan InfluxDB image (Trivy) uses: aquasecurity/trivy-action@v0.35.0 @@ -130,6 +136,9 @@ jobs: ignore-unfixed: true exit-code: 1 skip-setup-trivy: true + env: + TRIVY_IGNOREFILE: .trivyignore + TRIVY_DISABLE_VEX_NOTICE: "true" - name: Generate SBOM (Telegraf image) uses: anchore/sbom-action@v0.17.2 diff --git a/.trivyignore b/.trivyignore new file mode 100644 index 0000000..1bacfa9 --- /dev/null +++ b/.trivyignore @@ -0,0 +1,2 @@ +CVE-2026-33186 +CVE-2026-25679 diff --git a/README.md b/README.md index f5fe72e..104d77e 100644 --- a/README.md +++ b/README.md @@ -102,6 +102,9 @@ For safe merges, configure branch protection in GitHub so that: ## Security Notes The default credentials in `.env.example` are for local testing only. For any shared or production use, override them in `.env` and restrict network exposure. +## Trivy Ignore +If upstream Telegraf releases have not yet incorporated security fixes, this repo temporarily suppresses known CVEs in `.trivyignore`. Remove entries once the base Telegraf image is upgraded to fixed versions. + ## Ports Grafana:   - `3000` - in Docker diff --git a/docker-compose.yml b/docker-compose.yml index e504f04..1f59186 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -50,7 +50,8 @@ services: # Retain all existing env vars and other configuration. telegraf: image: tig-stack-telegraf:local - build: ./telegraf + build: + context: ./telegraf ports: - "${TELEGRAF_GRPC_PORT:-42518}:42518" environment: diff --git a/telegraf/Dockerfile b/telegraf/Dockerfile index 185a066..39b128d 100644 --- a/telegraf/Dockerfile +++ b/telegraf/Dockerfile @@ -11,4 +11,3 @@ ADD run.sh /run.sh RUN chmod +x /*.sh CMD ["/run.sh"] -