diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index 1783ed7..3cedeb6 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -1,5 +1,5 @@ # Dockerfile -FROM docker.io/golang:latest +FROM docker.io/golang:1.22.6 RUN apt-get update &&\ apt-get upgrade -y &&\ diff --git a/.github/workflows/build_and_publish.yml b/.github/workflows/build_and_publish.yml new file mode 100644 index 0000000..c2a2a74 --- /dev/null +++ b/.github/workflows/build_and_publish.yml @@ -0,0 +1,64 @@ +name: Build and Publish + +on: + push: + branches: + - main + +env: + REGISTRY: ghcr.io + IMAGE_NAME: ${{ github.repository }} + +jobs: + build_and_publish: + name: Build and Publish + runs-on: ubuntu-latest + + permissions: + contents: read + packages: write + attestations: write + id-token: write + + steps: + - name: Checkout Code + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + + - name: Set up Go + uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0 + with: + go-version: "1.22.6" + check-latest: false + + - name: Build Executable + run: | + go build ./cmd/jb-sw-realm + + - name: Login to GitHub Container Registry + uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Extract metadata (tags, labels) for Docker + id: meta + uses: docker/metadata-action@902fa8ec7d6ecbf8d84d538b9b233a880e428804 # v5.7.0 + with: + images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} + + - name: Build and push Docker image + id: push + uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6.18.0 + with: + context: . + push: true + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + + - name: Generate artifact attestation + uses: actions/attest-build-provenance@e8998f949152b193b063cb0ec769d69d929409be # v2.4.0 + with: + subject-name: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME}} + subject-digest: ${{ steps.push.outputs.digest }} + push-to-registry: true diff --git a/.github/workflows/lint_and_test.yml b/.github/workflows/lint_and_test.yml new file mode 100644 index 0000000..ce4242e --- /dev/null +++ b/.github/workflows/lint_and_test.yml @@ -0,0 +1,46 @@ +name: Lint and Test + +on: + pull_request: {} + workflow_dispatch: {} + +jobs: + lint_and_test: + name: Lint and Test + runs-on: ubuntu-latest + steps: + - name: Checkout Code + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + + - name: Set up Go + uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0 + with: + go-version: "1.22.6" + check-latest: false + + - name: Run revive (v1.10.0) + run: | + go install github.com/mgechev/revive@6becd540e4f864330381c0f2cd0cf05089aa8aa3 + revive -config revive.toml -formatter friendly ./... + + - name: Run staticcheck (v0.6.1) + run: | + go install honnef.co/go/tools/cmd/staticcheck@b8ec13ce4d00445d75da053c47498e6f9ec5d7d6 + staticcheck ./... + + - name: Run govulncheck (v1.1.4) + run: | + go version + go install golang.org/x/vuln/cmd/govulncheck@d1f380186385b4f64e00313f31743df8e4b89a77 + govulncheck ./... + + - name: Run go test + run: go test -v ./... + + - name: Build Executables + run: | + go build ./cmd/jb-sw-realm + go build ./cmd/tenant_log + + - name: Run go mod tidy + run: go mod tidy && git diff --quiet diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml deleted file mode 100644 index 78be7fc..0000000 --- a/.github/workflows/main.yml +++ /dev/null @@ -1,49 +0,0 @@ -name: CI - -on: - pull_request: {} - push: - branches: - - main - workflow_dispatch: {} - -jobs: - lint_and_test: - name: Lint and Test - runs-on: ubuntu-latest - steps: - - name: Checkout Code - uses: actions/checkout@v3 - - - name: Set up Go - uses: actions/setup-go@v3 - with: - go-version: '1.22.6' - check-latest: false - - - name: Run revive - run: | - go install github.com/mgechev/revive@latest - revive -config revive.toml -formatter friendly -set_exit_status ./... - - - name: Run staticcheck - run: | - go install honnef.co/go/tools/cmd/staticcheck@latest - staticcheck ./... - - - name: Run govulncheck - run: | - go version - go install golang.org/x/vuln/cmd/govulncheck@latest - govulncheck ./... - - - name: Run go test - run: go test -v ./... - - - name: Build Executables - run: | - go build ./cmd/jb-sw-realm - go build ./cmd/tenant_log - - - name: Run go mod tidy - run: go mod tidy && git diff --quiet diff --git a/Dockerfile b/Dockerfile index 3565104..af0b3df 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,31 +1,8 @@ -FROM golang:1.22.6 as build-env +FROM debian:latest -WORKDIR /app +RUN apt update && apt install -y ca-certificates -COPY go.mod go.sum ./ - -RUN go mod download - -COPY . . - -RUN CGO_ENABLED=0 go build -o /jb-sw-realm ./cmd/jb-sw-realm - -FROM debian:11-slim - -RUN apt-get update && apt-get install -y curl supervisor - -WORKDIR /otel - -RUN curl -LO https://github.com/open-telemetry/opentelemetry-collector-releases/releases/download/v0.77.0/otelcol-contrib_0.77.0_linux_amd64.tar.gz \ - && tar -xzvf otelcol-contrib_0.77.0_linux_amd64.tar.gz \ - && mv otelcol-contrib /usr/local/bin/otelcol-contrib \ - && rm -rf /otel - -COPY otel-collector-config.yaml /etc/otelcol-contrib/config.yaml - -COPY supervisord.conf /etc/supervisor/conf.d/supervisord.conf - -COPY --from=build-env /jb-sw-realm /usr/local/bin/jb-sw-realm +COPY jb-sw-realm /usr/local/bin/jb-sw-realm ENV PORT 8080 @@ -33,4 +10,4 @@ EXPOSE 8080 HEALTHCHECK CMD curl --fail "http://localhost:8080" || exit 1 -ENTRYPOINT ["/usr/bin/supervisord", "-c", "/etc/supervisor/conf.d/supervisord.conf"] +ENTRYPOINT ["/usr/local/bin/jb-sw-realm"] diff --git a/gcp/run.tf b/gcp/run.tf index 98a760f..7d3beb4 100644 --- a/gcp/run.tf +++ b/gcp/run.tf @@ -10,8 +10,18 @@ resource "google_cloud_run_v2_service" "juicebox" { template { timeout = "300s" service_account = google_service_account.service_account.email + volumes { + name = "otel-config" + secret { + secret = google_secret_manager_secret.opentelemetry_configuration.secret_id + items { + version = "latest" + path = "config.yaml" + } + } + } containers { - name = "juicebox-1" + name = "jb-sw-realms" ports { name = "http1" container_port = 8080 @@ -49,6 +59,10 @@ resource "google_cloud_run_v2_service" "juicebox" { name = "REALM_ID" value = var.realm_id } + env { + name = "OPENTELEMETRY_ENDPOINT" + value = "localhost:4317" + } dynamic "env" { for_each = var.juicebox_vars content { @@ -57,11 +71,27 @@ resource "google_cloud_run_v2_service" "juicebox" { } } } - } - lifecycle { - ignore_changes = [ - client - ] + containers { + name = "otel-collector" + resources { + limits = { + cpu = "1" + memory = "512Mi" + } + } + image = "${var.otelcol_image_url}:${var.otelcol_image_version}" + volume_mounts { + name = "otel-config" + mount_path = "/etc/otelcol-contrib/" + } + dynamic "env" { + for_each = var.otelcol_vars + content { + name = env.key + value = env.value + } + } + } } } @@ -73,6 +103,22 @@ resource "google_project_iam_binding" "logs_writer_binding" { ] } +resource "google_project_iam_binding" "metrics_writer_binding" { + project = var.project_id + role = "roles/monitoring.metricWriter" + members = [ + "serviceAccount:${google_service_account.service_account.email}" + ] +} + +resource "google_project_iam_binding" "cloud_trace_agent_binding" { + project = var.project_id + role = "roles/cloudtrace.agent" + members = [ + "serviceAccount:${google_service_account.service_account.email}" + ] +} + resource "google_cloud_run_v2_service_iam_binding" "allow_unauthenticated_users" { project = var.project_id name = google_cloud_run_v2_service.juicebox.name diff --git a/gcp/secret-manager.tf b/gcp/secret-manager.tf index f3c8753..87c423a 100644 --- a/gcp/secret-manager.tf +++ b/gcp/secret-manager.tf @@ -21,3 +21,25 @@ resource "google_secret_manager_secret_iam_binding" "access" { "serviceAccount:${google_service_account.service_account.email}" ] } + +resource "google_secret_manager_secret" "opentelemetry_configuration" { + secret_id = "jb-sw-otel-config" + replication { + auto {} + } +} + +resource "google_secret_manager_secret_version" "opentelemetry_configuration" { + secret = google_secret_manager_secret.opentelemetry_configuration.id + secret_data = var.otelcol_config_b64 == "INTERNAL" ? file("../otel-collector-config.yaml") : base64decode(var.otelcol_config_b64) +} + +resource "google_secret_manager_secret_iam_binding" "opentelemetry_configuration" { + for_each = var.tenant_secrets + secret_id = google_secret_manager_secret.opentelemetry_configuration.id + role = "roles/secretmanager.secretAccessor" + + members = [ + "serviceAccount:${google_service_account.service_account.email}" + ] +} diff --git a/gcp/variables.tf b/gcp/variables.tf index 0d0b47f..2c1800c 100644 --- a/gcp/variables.tf +++ b/gcp/variables.tf @@ -38,3 +38,26 @@ variable "juicebox_vars" { type = map(string) default = {} } + +variable "otelcol_image_url" { + description = "The url of the opentelemetry collector docker image" + type = string +} + +variable "otelcol_image_version" { + description = "The version of the opentelemetry collector docker image" + type = string +} + +variable "otelcol_config_b64" { + description = "A configuration file for the OpenTelemetry Collector, encoded in base64" + type = string + default = "INTERNAL" + # This default is captured in secret-manager.tf to deploy ../otel-collector-config.yaml from this repository. +} + +variable "otelcol_vars" { + description = "Environment variables for the juicebox container" + type = map(string) + default = {} +} diff --git a/revive.toml b/revive.toml index 0388299..123f6cd 100644 --- a/revive.toml +++ b/revive.toml @@ -1,7 +1,7 @@ ignoreGeneratedHeader = false severity = "warning" confidence = 0.8 -errorCode = 0 +errorCode = 1 warningCode = 0 [rule.blank-imports] diff --git a/supervisord.conf b/supervisord.conf deleted file mode 100644 index 581910d..0000000 --- a/supervisord.conf +++ /dev/null @@ -1,22 +0,0 @@ -[supervisord] -nodaemon=true -logfile=/dev/null -logfile_maxbytes=0 - -[program:jb-sw-realm] -command=/usr/local/bin/jb-sw-realm -autorestart=true -autostart=true -stdout_logfile=/dev/fd/1 -stdout_logfile_maxbytes=0 -stderr_logfile=/dev/fd/2 -stderr_logfile_maxbytes=0 - -[program:otel-collector] -command=/usr/local/bin/otelcol-contrib --config /etc/otelcol-contrib/config.yaml -autorestart=true -autostart=true -stdout_logfile=/dev/fd/1 -stdout_logfile_maxbytes=0 -stderr_logfile=/dev/fd/2 -stderr_logfile_maxbytes=0