diff --git a/Dockerfile b/Dockerfile index 79daa371..4befce9e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -12,8 +12,9 @@ # The Debian version and version name must be in sync ARG DEBIAN_VERSION=11 ARG DEBIAN_VERSION_NAME=bullseye -ARG RUSTC_VERSION=1.60.0 +ARG RUSTC_VERSION=1.61.0 ARG NODEJS_VERSION=16 +ARG OPA_VERSION=0.40.0 ## Build stage that builds the static files/frontend ## FROM --platform=${BUILDPLATFORM} docker.io/library/node:${NODEJS_VERSION}-${DEBIAN_VERSION_NAME}-slim AS static-files @@ -26,6 +27,21 @@ RUN npm run build # Change the timestamp of built files for better caching RUN find public -type f -exec touch -t 197001010000.00 {} + +## Build stage that builds the OPA policies ## +FROM --platform=${BUILDPLATFORM} docker.io/library/debian:${DEBIAN_VERSION_NAME}-slim AS policy + +ARG BUILDOS +ARG BUILDARCH +ARG OPA_VERSION + +ADD --chmod=755 https://github.com/open-policy-agent/opa/releases/download/v${OPA_VERSION}/opa_${BUILDOS}_${BUILDARCH}_static /usr/local/bin/opa + +WORKDIR /policies +COPY ./policies/ /policies +RUN opa build -t wasm -e "client_registration/allow" -e "login/allow" -e "register/allow" client_registration.rego login.rego register.rego \ + && tar xzf bundle.tar.gz /policy.wasm \ + && rm -f bundle.tar.gz + ## Base image with cargo-chef and the right cross-compilation toolchain ## # cargo-chef helps with caching dependencies between builds # The image Debian base name (bullseye) must be in sync with the runtime variant (debian11) @@ -106,9 +122,13 @@ RUN mv target/$(/docker-arch-to-rust-target.sh "${TARGETPLATFORM}")/release/mas- ## Runtime stage, debug variant ## FROM --platform=${TARGETPLATFORM} gcr.io/distroless/cc-debian${DEBIAN_VERSION}:debug-nonroot AS debug COPY --from=builder /usr/local/bin/mas-cli /usr/local/bin/mas-cli +COPY --chmod=444 --from=policy /policies/policy.wasm /policies/policy.wasm +WORKDIR / ENTRYPOINT ["/mas-cli"] ## Runtime stage ## FROM --platform=${TARGETPLATFORM} gcr.io/distroless/cc-debian${DEBIAN_VERSION}:nonroot COPY --from=builder /usr/local/bin/mas-cli /usr/local/bin/mas-cli +COPY --chmod=444 --from=policy /policies/policy.wasm /policies/policy.wasm +WORKDIR / ENTRYPOINT ["/usr/local/bin/mas-cli"] diff --git a/policies/register.rego b/policies/register.rego index c918288e..720fb263 100644 --- a/policies/register.rego +++ b/policies/register.rego @@ -3,7 +3,8 @@ package register import future.keywords.in default allow := false -allow := true { + +allow { count(violation) == 0 } @@ -12,7 +13,7 @@ violation[{"field": "username", "msg": "username too short"}] { } violation[{"field": "username", "msg": "username too long"}] { - count(input.user.username) >= 15 + count(input.user.username) >= 15 } # Allow any domains if the data.allowed_domains array is not set @@ -37,5 +38,3 @@ violation[{"field": "email", "msg": "email domain not allowed"}] { some banned_domain in data.banned_domains glob.match(banned_domain, ["."], domain) } - - diff --git a/policies/register_test.rego b/policies/register_test.rego index c84a4676..740e22cc 100644 --- a/policies/register_test.rego +++ b/policies/register_test.rego @@ -7,26 +7,30 @@ test_allow_all_domains { } test_allowed_domain { - allow - with input.user as mock_user + allow with input.user as mock_user with data.allowed_domains as ["*.element.io"] } test_not_allowed_domain { - not allow - with input.user as mock_user + not allow with input.user as mock_user with data.allowed_domains as ["example.com"] } test_banned_domain { - not allow - with input.user as mock_user + not allow with input.user as mock_user with data.banned_domains as ["*.element.io"] } test_banned_subdomain { - not allow - with input.user as mock_user + not allow with input.user as mock_user with data.allowed_domains as ["*.element.io"] with data.banned_domains as ["staging.element.io"] } + +test_short_username { + not allow with input.user as {"username": "a", "email": "hello@element.io"} +} + +test_long_username { + not allow with input.user as {"username": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "email": "hello@element.io"} +}