-
Notifications
You must be signed in to change notification settings - Fork 12
Expand file tree
/
Copy pathDockerfile
More file actions
411 lines (374 loc) · 23.6 KB
/
Copy pathDockerfile
File metadata and controls
411 lines (374 loc) · 23.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
ARG OPA_BUILD=permit
# RUST BUILD STAGE -----------------------------------
# Build the Rust PDP binary for all targets
# ----------------------------------------------------
# BIG thanks to
# - https://medium.com/@vladkens/fast-multi-arch-docker-build-for-rust-projects-a7db42f3adde
# - https://stackoverflow.com/questions/70561544/rust-openssl-could-not-find-directory-of-openssl-installation
# couldn't get this to work without the help of those two sources
# (1) this stage will be run always on current arch
# zigbuild & Cargo targets added
FROM --platform=$BUILDPLATFORM rust:1.94-alpine AS rust_chef
WORKDIR /app
ENV PKGCONFIG_SYSROOTDIR=/
RUN apk add --no-cache musl-dev openssl-dev zig pkgconf perl make
# Cache cargo installations
RUN --mount=type=cache,target=/usr/local/cargo/registry \
--mount=type=cache,target=/usr/local/cargo/git \
cargo install --locked cargo-zigbuild cargo-chef
RUN rustup target add x86_64-unknown-linux-musl aarch64-unknown-linux-musl
# (2) nothing changed
FROM rust_chef AS rust_planner
COPY . .
RUN cargo chef prepare --recipe-path recipe.json
# (3) building project deps: need to specify all targets; zigbuild used
FROM rust_chef AS rust_builder
COPY --from=rust_planner /app/recipe.json recipe.json
ENV OPENSSL_DIR=/usr
# Enable incremental compilation and use cache mounts
ENV CARGO_INCREMENTAL=1
RUN --mount=type=cache,target=/usr/local/cargo/registry \
--mount=type=cache,target=/usr/local/cargo/git \
--mount=type=cache,target=/app/target \
cargo chef cook --recipe-path recipe.json --release --zigbuild \
--target x86_64-unknown-linux-musl --target aarch64-unknown-linux-musl
# (4) actual project build for all targets
# binary renamed to easier copy in runtime stage
COPY . .
# Use cache mounts for incremental builds - this is the key optimization!
RUN --mount=type=cache,target=/usr/local/cargo/registry \
--mount=type=cache,target=/usr/local/cargo/git \
--mount=type=cache,target=/app/target \
cargo zigbuild -r --target x86_64-unknown-linux-musl --target aarch64-unknown-linux-musl && \
mkdir -p /app/linux/arm64/ && \
mkdir -p /app/linux/amd64/ && \
cp target/aarch64-unknown-linux-musl/release/pdp-server /app/linux/arm64/pdp && \
cp target/x86_64-unknown-linux-musl/release/pdp-server /app/linux/amd64/pdp
# OPA BUILD STAGE -----------------------------------
# Build OPA from source or download precompiled binary
# ---------------------------------------------------
# Go 1.26 builder (was golang:1.25-bookworm), landing AHEAD of permit-opa moving its
# `go` directive to 1.26 (permitio/permit-opa#52, stacked on #51). That move is forced
# by golang.org/x/crypto >= 0.56.0 - the version that clears CVE-2026-78662 /
# CVE-2026-56855 (x/crypto/ssh), waived today in .docker/scout/pdp-v2.vex.json - whose
# own go.mod declares `go 1.26.0`.
#
# The order only works one way. tests.yml and release.yml check out
# permitio/permit-opa at `ref: main`, unpinned, so a permit-opa merge reaches the very
# next PDP build. With GOTOOLCHAIN=local (set below; the official golang images set it
# too), a 1.25 builder facing a `go 1.26` module does not fetch a newer toolchain - it
# hard-fails:
#
# go: go.mod requires go >= 1.26.0 (running go 1.25.x; GOTOOLCHAIN=local)
#
# and build-pdp-image breaks. A 1.26 builder compiling today's `go 1.25.0` module is
# forward-compatible, so this bump is safe to land on its own, ahead of that.
#
# Merging this does NOT end that exposure, it only ends it on main. release.yml checks
# THIS repo out with no `ref:` (:25-26) while still taking permit-opa from `ref: main`
# (:40-43), so a release builds the Dockerfile of the commit it was cut from against
# today's permit-opa; tests.yml also builds on any push to a `v*` branch (:6). The
# newest tag, v0.9.15, is d3da8b9 - this PR's base - whose opa_build is still
# golang:1.25-bookworm. So the rule that outlives this PR, for as long as the
# permit-opa checkout is unpinned: once permit-opa#52 merges, every pdp-v2 release and
# every `v*` branch build must come from a commit containing this FROM line. Backport
# it before cutting a hotfix or re-running a release from an older tag. permit-opa's
# `pdp-builder` check (see the FROM-line note below) hands the releaser this same rule
# and says in so many words that it cannot enforce it, because it only ever reads this
# file on main. Pinning the permit-opa checkout to a tag removes the whole class.
#
# What changes in /app/bin/opa: changes that come with the 1.26 toolchain land with
# this builder (e.g. the Green Tea GC is on by default). GODEBUG-gated defaults do not:
# they follow permit-opa's go.mod - its `go 1.25.0` today, and after permit-opa#52 a
# `godebug default=go1.25` line. Removing that line in permit-opa changes this binary
# on the next PDP build, with no change here.
# The binary is CGO_ENABLED=0 (below), so the builder's glibc does not reach the image.
#
# The patch version floats with the tag (go1.26.8 today) on purpose: a Go security
# release reaches the next build with no change here.
#
# TWO PARAGRAPHS HERE GO STALE WHEN PDP#338 LANDS (open, head 2e8a313) - this one and
# the auditability one below. #338 digest-pins this FROM line and adds a docker
# Dependabot entry, daily but with `cooldown: default-days: 7`, so "with no change
# here" becomes "Dependabot moves tag and digest together, a week after the Go release
# publishes". It also drops docker-scout's `pull_request` gate and adds
# image-scan-published.yml (`cron: '17 6 * * *'`), which CLOSES the gap the
# auditability paragraph describes rather than recording it.
#
# This stage pins nothing beyond that floor, and that is a statement about THIS builder
# only. permit-opa builds its own artifacts - its own Dockerfile, its own release
# workflow - and its toolchain policy is set in those files, not here. PER-16045
# proposes pinning its release binaries to an exact toolchain (permit-opa#51) and
# putting its image on this same go1.26.6 floor (permit-opa#52); both are open, so read
# permit-opa's own tree for what it does today rather than inferring it from here.
#
# Auditability: the toolchain is recorded in the binary's build info, survives `-s -w`,
# and is readable with `go version` on an extracted copy - extracted, because the
# runtime base is python:3.13-alpine3.23 and ships no Go. That is an after-the-fact
# audit, not a gate. Until PDP#338 lands, the only scanner in this repo is the
# docker-scout job, which is `pull_request`-only and points at a local tag, so no
# published pdp-v2 tag is ever re-scanned (tests.yml says so itself; PER-15358) - and
# the release build re-resolves this tag weeks later, for both arches, with nothing
# reading either.
#
# The floor is go1.26.6, the first 1.26 release with the crypto/tls fix for
# GO-2026-6090, and the RUN below fails the build on anything older (e.g. a stale local
# image). It prints the version it accepted, but it is a GATE, not a record: it caches
# on the base image digest, so it only re-runs when the tag moves, and in a release log
# it usually reads CACHED with that version sitting in whichever earlier run first saw
# the digest - subject to log retention. The compile RUN below echoes the toolchain too,
# and that one is reliable: `COPY custom* /custom` sees a tarball the workflow
# regenerates every run, so the stage re-executes from that COPY on and the echo is
# always in the log of the build that produced the binary. For an already-published
# image, `go version` on the extracted binary (above) needs no build log at all.
# The floor binds only the branch below that compiles permit-opa (custom_opa.tar.gz
# present); the fallback without the tarball downloads a prebuilt OPA - unpinned
# (`latest`) and unverified (no --fail, no checksum). PER-16045.
#
# KEEP THE SHAPE OF THE FROM LINE: permit-opa's `pdp-builder` check (permit-opa#52)
# fetches this Dockerfile from main and greps this line for a literal
# `golang:<major>.<minor>` on a line ending in `AS opa_build`. Setting the version from
# an ARG, splitting the FROM across lines or renaming the stage turns permit-opa's CI
# red with "cannot compare go.mod's directive" - which is a fail-closed by design, but
# it will look like an unrelated repo breaking for no reason.
FROM golang:1.26-bookworm AS opa_build
ENV GOTOOLCHAIN=local
RUN v=$(go env GOVERSION) && \
[ "$(printf '%s\n' go1.26.6 "$v" | sort -V | head -n1)" = go1.26.6 ] || \
{ echo "opa_build: $v is below the go1.26.6 floor (GO-2026-6090)"; exit 1; } && \
echo "opa_build: building with $v"
COPY custom* /custom
# Build OPA binary if custom_opa.tar.gz is provided
# Fix for ARM64 compatibility issue (#289): Build fully static binary to avoid dynamic linking issues
# Problem: Dynamic linking creates dependencies on system libc (glibc), but Alpine Linux uses musl libc
# Result: Binary fails with "/lib/ld-musl-aarch64.so.1: /app/bin/opa: Not a valid dynamic program"
# Solution: Build a truly static binary with no external libc dependencies
# - CGO_ENABLED=0: Disables CGO to ensure pure Go compilation (eliminates glibc dependency)
# - -a: Forces rebuilding of all packages to ensure clean static build
# - -tags netgo: Uses pure Go network stack instead of C-based libc resolver
# - -s -w: Strips debug info and symbol table to reduce binary size
# - -extldflags=-static: Ensures static linking if CGO were enabled (defense in depth)
# Use BuildKit cache mounts for Go modules and build cache for MUCH faster incremental builds
RUN --mount=type=cache,target=/go/pkg/mod \
--mount=type=cache,target=/root/.cache/go-build \
if [ -f /custom/custom_opa.tar.gz ]; \
then \
cd /custom && \
tar xzf custom_opa.tar.gz && \
# This RUN never comes from cache - `COPY custom* /custom` above sees a tarball the
# workflow regenerates every build - so this echo is the toolchain record for THIS
# build. The floor check above is the gate, and usually reads CACHED.
echo "opa_build: compiling permit-opa with $(go env GOVERSION)" && \
# permit-opa moved its main package from the repo root to ./cmd/opa
# (cmd/ + pkg/ layout); build whichever location the tarball provides
if [ -d cmd/opa ]; then main_pkg=./cmd/opa; else main_pkg=.; fi && \
CGO_ENABLED=0 go build -a -ldflags="-s -w -extldflags=-static" -tags netgo -installsuffix netgo -o /opa $main_pkg && \
rm -rf /custom; \
else \
case $(uname -m) in \
x86_64) curl -L -o /opa https://openpolicyagent.org/downloads/latest/opa_linux_amd64_static ;; \
aarch64) curl -L -o /opa https://openpolicyagent.org/downloads/latest/opa_linux_arm64_static ;; \
*) echo "Unknown architecture." && exit 1 ;; \
esac; \
fi
# MAIN IMAGE ----------------------------------------
# Main image setup (optimized)
# ---------------------------------------------------
# Python 3.13 (>= 3.13.14) on Alpine 3.23. Moved off python:3.10-alpine3.22 to clear four
# CPython CVEs a customer CPE scan raised against pdp-v2 0.9.14-rc1 (PER-15358):
# CVE-2026-6019 (http.cookies Morsel.js_output escaping) - fixed in 3.13.14
# CVE-2026-7210 (expat hash-flooding entropy) - fixed in 3.13.14 AND needs
# libexpat >= 2.8.0; this image
# ships expat 2.8.1
# CVE-2023-36632 (email.utils.parseaddr recursion) - DISPUTED by PSF and never
# fixed, but its CPE range is
# < 3.11.4, so 3.13 is out of it
# PSF fixed these only on the 3.13/3.14/3.15 branches - there is no 3.10/3.11/3.12 backport -
# so the vulnerable code really was present in 3.10.20 and an upgrade was the only fix.
# CVE-2026-15308 (html.parser CPU-exhaustion DoS) is now cleared too: it was waived here as
# unreachable while it was patched only in 3.15.0b4, but CPython backported the fix and it
# landed in 3.13.15 (also 3.14.7). The base tag floats, so the current build resolves
# 3.13.15 and the waiver has been REMOVED from .docker/scout/pdp-v2.vex.json.
# Do not drop below the patched floor for whichever branch the base resolves to: 3.13.15 on
# the 3.13 line, 3.14.7 on 3.14. The apk layer below enforces exactly that, per branch -
# a flat `>= (3,13,15)` would have passed 3.14.0 through 3.14.6, which are the versions the
# line above says still lack the backport.
#
# Removing the CVE-2026-15308 waiver is NOT what enforces it. Scout indexes the interpreter
# - `docker scout sbom` reports `pkg:generic/python@3.13.15` for this base - but it does not
# match CPython advisories against it the way a CPE-based scanner does (see the NOTE in
# tests.yml), and the gate is `pull_request`-only so a release never scans at all. Catching
# a stale interpreter through a scanner needs a CPE-based one; that is the companion change
# under PER-15358. The plain reason the waiver could go is simply that 3.13.15 carries the
# fix.
#
# The check imports the C extension modules DIRECTLY - `_ssl`, `_hashlib`, `_decimal` and
# friends rather than `ssl`, `hashlib`, `decimal` - and that is the point, not decoration.
# `sys` is a builtin, so `import sys` alone loads no extension modules at all and a
# version-only check would pass on an interpreter whose lib-dynload is unresolvable. But
# the public wrappers are not reliable either: decimal.py and hashlib.py both fall back
# silently to pure Python when their .so is missing, so importing them detects nothing,
# while ssl/zlib/lzma/bz2/ctypes/pyexpat do propagate. Importing the underscore modules
# removes that asymmetry. Between them these nine cover libssl, libcrypto, libz, liblzma,
# libbz2, libffi, libuuid and lib-dynload itself - i.e. the `so:` deps the .python-rundeps
# rework above could strip if its `grep '^so:'` list ever comes back short. Deliberately
# NOT extended to readline/_curses/_gdbm: they guard libs the PDP never uses, and `_gdbm`
# is absent from some perfectly good CPython builds, so requiring it would fail the build
# for no security reason.
#
# It uses sys.exit rather than `assert`, which -O / PYTHONOPTIMIZE strips. A cached `main`
# layer skips the check, but a cache hit implies an unchanged parent and so an unchanged
# base digest, so the floor still holds; both workflows pass `no-cache-filters: main`
# regardless. Note the check runs in this apk layer, before the `.build-deps` install and
# removal around `pip install` further down - so it proves the interpreter survived the
# sqlite surgery, not that it survives every later package mutation.
#
# The patch version floats deliberately (see the previous python:3.10-alpine3.22 base and
# the rebuild-picks-it-up posture in PER-15532). Note what that posture costs if nothing
# ever rebuilds: see the apk note below.
#
# Python 3.10 also reaches end of life in October 2026, so this move was due regardless.
FROM python:3.13-alpine3.23 AS main
WORKDIR /app
# Create necessary user and group in a single step
RUN addgroup -S permit -g 1001 && \
adduser -S -s /bin/bash -u 1000 -G permit -h /home/permit permit
# Create backup directory with permissions
RUN mkdir -p /app/backup && chmod -R 777 /app/backup
# Install runtime libraries and remove sqlite-libs.
# Build deps (build-base, *-dev) are installed and removed in the pip install
# layer to avoid persisting binutils CVEs (CVE-2025-69649, CVE-2025-69650).
#
# `apk upgrade` here is the ONLY thing that keeps the OS package set current, and it is
# only as fresh as the build that ran it. permitio/pdp-v2:0.9.14 was built 2026-08-04 and
# pinned libcrypto3/libssl3 3.5.7-r0 + libuuid 2.41.4-r0 at that moment. Alpine 3.23 later
# published openssl 3.5.8-r0 and util-linux 2.41.6-r1, so by 2026-09-09 a customer CPE scan
# of the UNCHANGED published tag reported 12 CVEs / 21 findings - nine OpenSSL
# (CVE-2026-14456, CVE-2026-14457, CVE-2026-18798, CVE-2026-54874, CVE-2026-63072,
# CVE-2026-63073, CVE-2026-63075, CVE-2026-63076, CVE-2026-75803) and three util-linux.
# Not one of them was a source defect: this Dockerfile was already correct, and a rebuild
# with no edits produces 0 findings. The image was simply never rebuilt. See PER-15358.
#
# Two consequences, both load-bearing:
# 1. Release builds MUST NOT serve this layer from cache. release.yml uses
# `cache-from: type=gha`, and the cache key is this instruction text plus the parent
# layer - so a release cut months later could replay the 2026-08-04 apk layer and
# re-ship the exact packages a customer just flagged. release.yml therefore passes
# `no-cache-filters: main` to force that stage to re-resolve on every release, and
# tests.yml passes the same value so the scanned image is not built on a stale
# package set either. That is the guarantee - NOT that the two images match. They
# are two independent fresh resolutions against the live Alpine/PyPI indexes,
# tests.yml builds linux/amd64 only while release.yml builds amd64+arm64, and the
# scout gate is `pull_request`-only so the release build is never the one scanned.
# Closing that last gap needs the gate to run on release events (PER-15358).
# 2. A tag that is never rebuilt rots on its own, and no build-time gate can catch that:
# the docker-scout gate in tests.yml runs only on pull_request, so it scanned this
# image in July and could not possibly have seen CVEs disclosed in September.
# Detecting drift therefore REQUIRES re-scanning the PUBLISHED tags on a schedule.
# Deliberately phrased as a requirement, not a description: no workflow in this repo
# has a `schedule:` trigger, so nothing here does it yet. That is the job of the
# companion change tracked under PER-15358.
#
# The PDP never uses SQLite, but its FTS5/zipfile CVEs (CVE-2026-11822,
# CVE-2026-11824, CVE-2025-70873) are still reported against sqlite-libs, which
# the official python:alpine image pins via the .python-rundeps virtual package.
# A plain `apk del sqlite-libs` is refused (that pin), and deleting the virtual
# cascade-purges the whole python runtime. So re-pin every OTHER python runtime
# shared object under a fresh virtual (derived dynamically, so it is
# arch-agnostic), then drop the original pin together with sqlite-libs.
RUN --mount=type=cache,target=/var/cache/apk \
ln -s /var/cache/apk /etc/apk/cache && \
apk update && \
apk upgrade && \
apk add bash libffi libressl gcompat && \
apk add --no-cache --virtual .python-rundeps-nosqlite \
$(apk info -qR .python-rundeps | grep '^so:' | grep -v 'libsqlite3') && \
apk del .python-rundeps sqlite-libs && \
python3 -c "import sys, _ssl, _hashlib, _decimal, zlib, _lzma, _bz2, _ctypes, pyexpat, _uuid; v = sys.version_info[:3]; v >= {13: (3, 13, 15), 14: (3, 14, 7)}.get(v[1], (3, 15, 0)) or sys.exit('CPython %s is below the patched floor for its branch' % sys.version)"
# Copy OPA binary from the build stage
COPY --from=opa_build --chmod=755 /opa /app/bin/opa
# Copy the Rust PDP binary from the builder stage
ARG TARGETPLATFORM
COPY --from=rust_builder --chmod=755 /app/${TARGETPLATFORM}/pdp /app/pdp
# Environment variables for OPA
ENV OPAL_INLINE_OPA_EXEC_PATH="/app/bin/opa"
# Set permissions and ownership for the application
RUN mkdir -p /config && chown -R permit:permit /config
# Ensure the `permit` user has the correct permissions for home directory and binaries
RUN chown -R permit:permit /home/permit /app /usr/local/bin
# Copy Kong routes and Gunicorn config
COPY kong_routes.json /config/kong_routes.json
# Install python dependencies in one command to optimize layer size
# Use cache mount for pip to speed up incremental builds
COPY ./requirements.txt ./requirements.txt
RUN --mount=type=cache,target=/root/.cache/pip \
apk add --no-cache --virtual .build-deps build-base libffi-dev libressl-dev musl-dev zlib-dev && \
pip install --upgrade pip setuptools && \
pip install -r requirements.txt && \
python -m pip uninstall -y pip setuptools wheel && \
rm -r "$(python3 -c 'import sysconfig; print(sysconfig.get_paths()["stdlib"])')/ensurepip" && \
apk del .build-deps
USER permit
# Copy the application code
COPY ./horizon /app/horizon
# Version file for the application
COPY ./permit_pdp_version /app/permit_pdp_version
# Set the PATH to ensure the local binary paths are used
ENV PATH="/app/bin:/home/permit/.local/bin:$PATH"
# opal configuration --------------------------------
ENV OPAL_SERVER_URL="https://opal.permit.io"
ENV OPAL_LOG_DIAGNOSE="false"
ENV OPAL_LOG_TRACEBACK="false"
ENV OPAL_LOG_MODULE_EXCLUDE_LIST="[]"
ENV OPAL_INLINE_OPA_ENABLED="true"
ENV OPAL_INLINE_OPA_LOG_FORMAT="http"
# datadog / ddtrace configuration -------------------
# Drop "baggage" from ddtrace's default extract styles ("datadog,tracecontext,baggage").
# CVE-2026-50271: ddtrace's W3C baggage propagator does not enforce
# DD_TRACE_BAGGAGE_MAX_ITEMS / DD_TRACE_BAGGAGE_MAX_BYTES on the *extract* path, so an
# unauthenticated caller can force unbounded CPU/memory use with an oversized baggage
# header. The fix is only in ddtrace >= 4.8.2, which opal-common's `ddtrace<4,>=3.0.0`
# cap forbids, so we remove the vulnerable parser from the request path instead.
#
# This only matters when PDP_ENABLE_MONITORING=true (default false) - that is what calls
# patch(fastapi=True) and puts ddtrace on the inbound request path at all. Injection is
# left at its default, so outbound baggage propagation is unaffected. Remove this once
# OPAL relaxes its ddtrace<4 bound and ddtrace moves to >= 4.8.2. See PER-15358.
ENV DD_TRACE_PROPAGATION_STYLE_EXTRACT="datadog,tracecontext"
# horizon configuration -----------------------------
# by default, the backend is at port 8000 on the docker host
# in prod, you must pass the correct url
ENV PDP_CONTROL_PLANE="https://api.permit.io"
ENV PDP_API_KEY="MUST BE DEFINED"
ENV PDP_REMOTE_CONFIG_ENDPOINT="/v2/pdps/me/config"
ENV PDP_REMOTE_STATE_ENDPOINT="/v2/pdps/me/state"
ENV PDP_VERSION_FILE_PATH="/app/permit_pdp_version"
# This is a default PUBLIC (not secret) key,
# and it is here as a safety measure on purpose.
ENV OPAL_AUTH_PUBLIC_KEY="ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDe2iQ+/E01P2W5/EZwD5NpRiSQ8/r/k18pFnym+vWCSNMWpd9UVpgOUWfA9CAX4oEo5G6RfVVId/epPH/qVSL87uh5PakkLZ3E+PWVnYtbzuFPs/lHZ9HhSqNtOQ3WcPDTcY/ST2jyib2z0sURYDMInSc1jnYKqPQ6YuREdoaNdPHwaTFN1tEKhQ1GyyhL5EDK97qU1ejvcYjpGm+EeE2sjauHYn2iVXa2UA9fC+FAKUwKqNcwRTf3VBLQTE6EHGWbxVzXv1Feo8lPZgL7Yu/UPgp7ivCZhZCROGDdagAfK9sveYjkKiWCLNUSpado/E5Vb+/1EVdAYj6fCzk45AdQzA9vwZefP0sVg7EuZ8VQvlz7cU9m+XYIeWqduN4Qodu87rtBYtSEAsru/8YDCXBDWlLJfuZb0p/klbte3TayKnQNSWD+tNYSJHrtA/3ZewP+tGDmtgLeB38NLy1xEsgd31v6ISOSCTHNS8ku9yWQXttv0/xRnuITr8a3TCLuqtUrNOhCx+nKLmYF2cyjYeQjOWWpn/Z6VkZvOa35jhG1ETI8IwE+t5zXqrf2s505mh18LwA1DhC8L/wHk8ZG7bnUe56QwxEo32myUBN8nHdu7XmPCVP8MWQNLh406QRAysishWhXVs/+0PbgfBJ/FxKP8BXW9zqzeIG+7b/yk8tRHQ=="
# We ignore this callback because we are sunsetting this feature in favor of the new inline OPA data updater
ENV PDP_IGNORE_DEFAULT_DATA_UPDATE_CALLBACKS_URLS='["http://localhost:8181/v1/data/permit/rebac/cache_rebuild"]'
# We need to set v0_compatible to true to make sure the PDP works with the OPA v0
# syntax.
ENV OPAL_INLINE_OPA_CONFIG='{"v0_compatible": true}'
# if we are using the custom OPA binary, we need to load the permit plugin,
# if we don't then we MUST not add a non existing plugin
FROM main AS main-vanilla
# if we are using the vanilla OPA binary, we don't need to load the permit plugin
ENV PDP_OPA_PLUGINS='{}'
FROM main AS main-permit
# if we are using the custom OPA binary, we need to load the permit plugin,
ENV PDP_OPA_PLUGINS='{"permit_graph":{}}'
FROM main-${OPA_BUILD} AS application
# Environment variables with defaults
ENV PDP_HORIZON_HOST=0.0.0.0
ENV PDP_HORIZON_PORT=7001
ENV PDP_PORT=7000
ENV PDP_PYTHON_PATH=python3
ENV NO_PROXY=localhost,127.0.0.1,::1
# 7000 pdp port
# 7001 horizon port
# 8181 opa port
EXPOSE 7000 7001 8181
# Run the application using the startup script
CMD ["/app/pdp"]