mirror of
https://github.com/element-hq/matrix-authentication-service.git
synced 2026-10-23 04:23:18 +00:00
Do not embed the WASM-compiled policies in the binary
This commit is contained in:
1 parent
a86798d2b3
commit
834214bcac
20 files changed
+124
-92
No files matched your search
+13
-19
@@ -32,24 +32,21 @@ jobs:
|
||||
version: 0.45.0
|
||||
|
||||
- name: Lint policies
|
||||
run: |
|
||||
cd crates/policy/policies
|
||||
make lint
|
||||
working-directory: ./policies
|
||||
run: make lint
|
||||
|
||||
- name: Run OPA tests
|
||||
run: |
|
||||
cd crates/policy/policies
|
||||
make test
|
||||
working-directory: ./policies
|
||||
run: make test
|
||||
|
||||
- name: Run OPA tests with coverage
|
||||
run: |
|
||||
cd crates/policy/policies
|
||||
make coverage
|
||||
working-directory: ./policies
|
||||
run: make coverage
|
||||
|
||||
- name: Upload to codecov.io
|
||||
uses: codecov/codecov-action@v3
|
||||
with:
|
||||
files: crates/policy/policies/coverage.json
|
||||
files: policies/coverage.json
|
||||
flags: policies
|
||||
|
||||
frontend-lint:
|
||||
@@ -198,9 +195,8 @@ jobs:
|
||||
version: 0.45.0
|
||||
|
||||
- name: Compile OPA policies
|
||||
run: |
|
||||
cd crates/policy/policies
|
||||
make
|
||||
working-directory: ./policies
|
||||
run: make
|
||||
|
||||
- name: Setup Rust cache
|
||||
uses: Swatinem/rust-cache@v2
|
||||
@@ -259,9 +255,8 @@ jobs:
|
||||
version: 0.45.0
|
||||
|
||||
- name: Compile OPA policies
|
||||
run: |
|
||||
cd crates/policy/policies
|
||||
make
|
||||
working-directory: ./policies
|
||||
run: make
|
||||
|
||||
- name: Setup Rust cache
|
||||
uses: Swatinem/rust-cache@v2
|
||||
@@ -325,9 +320,8 @@ jobs:
|
||||
version: 0.45.0
|
||||
|
||||
- name: Compile OPA policies
|
||||
run: |
|
||||
cd crates/policy/policies
|
||||
make
|
||||
working-directory: ./policies
|
||||
run: make
|
||||
|
||||
- name: Setup Rust cache
|
||||
uses: Swatinem/rust-cache@v2
|
||||
|
||||
+6
-3
@@ -74,8 +74,8 @@ ARG OPA_VERSION
|
||||
# Download Open Policy Agent
|
||||
ADD --chmod=755 https://github.com/open-policy-agent/opa/releases/download/v${OPA_VERSION}/opa_${BUILDOS}_${BUILDARCH}_static /usr/local/bin/opa
|
||||
|
||||
WORKDIR /app/crates/policy/policies
|
||||
COPY ./crates/policy/policies/ /app/crates/policy/policies
|
||||
WORKDIR /app/policies
|
||||
COPY ./policies /app/policies
|
||||
RUN make -B
|
||||
|
||||
# Change the timestamp of built files for better caching
|
||||
@@ -148,7 +148,6 @@ RUN cargo chef cook \
|
||||
COPY ./Cargo.toml ./Cargo.lock /app/
|
||||
COPY ./crates /app/crates
|
||||
COPY --from=static-files /app/crates/static-files/public /app/crates/static-files/public
|
||||
COPY --from=policy /app/crates/policy/policies/policy.wasm /app/crates/policy/policies/policy.wasm
|
||||
ENV SQLX_OFFLINE=true
|
||||
RUN cargo auditable zigbuild \
|
||||
--locked \
|
||||
@@ -168,6 +167,8 @@ FROM --platform=${TARGETPLATFORM} gcr.io/distroless/cc-debian${DEBIAN_VERSION}:d
|
||||
|
||||
COPY --from=builder /usr/local/bin/mas-cli /usr/local/bin/mas-cli
|
||||
COPY --from=frontend /usr/local/share/mas-cli /usr/local/share/mas-cli
|
||||
COPY --from=policy /app/policies/policy.wasm /usr/local/share/mas-cli/policy.wasm
|
||||
|
||||
WORKDIR /
|
||||
ENTRYPOINT ["/usr/local/bin/mas-cli"]
|
||||
|
||||
@@ -178,5 +179,7 @@ FROM --platform=${TARGETPLATFORM} gcr.io/distroless/cc-debian${DEBIAN_VERSION}:n
|
||||
|
||||
COPY --from=builder /usr/local/bin/mas-cli /usr/local/bin/mas-cli
|
||||
COPY --from=frontend /usr/local/share/mas-cli /usr/local/share/mas-cli
|
||||
COPY --from=policy /app/policies/policy.wasm /usr/local/share/mas-cli/policy.wasm
|
||||
|
||||
WORKDIR /
|
||||
ENTRYPOINT ["/usr/local/bin/mas-cli"]
|
||||
@@ -11,16 +11,23 @@ See the [Documentation](https://matrix-org.github.io/matrix-authentication-servi
|
||||
- [Install Node.js and npm](https://nodejs.org/)
|
||||
- [Install Open Policy Agent](https://www.openpolicyagent.org/docs/latest/#1-download-opa)
|
||||
- Clone this repository
|
||||
- Generate the frontend:
|
||||
- Generate the static-files:
|
||||
```sh
|
||||
cd crates/static-files
|
||||
npm ci
|
||||
npm run build
|
||||
cd ../..
|
||||
```
|
||||
- Build the frontend
|
||||
```sh
|
||||
cd frontend
|
||||
npm ci
|
||||
npm run build
|
||||
cd ../..
|
||||
```
|
||||
- Build the Open Policy Agent policies
|
||||
```sh
|
||||
cd crates/policy/policies
|
||||
cd policies
|
||||
make
|
||||
# OR, if you don't have `opa` installed and want to build through the OPA docker image
|
||||
make DOCKER=1
|
||||
|
||||
@@ -18,7 +18,7 @@ use hyper::{Response, Uri};
|
||||
use mas_config::PolicyConfig;
|
||||
use mas_http::HttpServiceExt;
|
||||
use mas_policy::PolicyFactory;
|
||||
use tokio::io::{AsyncRead, AsyncWriteExt};
|
||||
use tokio::io::AsyncWriteExt;
|
||||
use tower::{Service, ServiceExt};
|
||||
use tracing::info;
|
||||
|
||||
@@ -121,19 +121,12 @@ impl Options {
|
||||
SC::Policy => {
|
||||
let config: PolicyConfig = root.load_config()?;
|
||||
info!("Loading and compiling the policy module");
|
||||
let mut policy: Box<dyn AsyncRead + std::marker::Unpin> =
|
||||
if let Some(path) = &config.wasm_module {
|
||||
Box::new(
|
||||
tokio::fs::File::open(path)
|
||||
.await
|
||||
.context("failed to open OPA WASM policy file")?,
|
||||
)
|
||||
} else {
|
||||
Box::new(mas_policy::default_wasm_policy())
|
||||
};
|
||||
let policy_file = tokio::fs::File::open(&config.wasm_module)
|
||||
.await
|
||||
.context("failed to open OPA WASM policy file")?;
|
||||
|
||||
let policy_factory = PolicyFactory::load(
|
||||
&mut policy,
|
||||
policy_file,
|
||||
config.data.clone().unwrap_or_default(),
|
||||
config.register_entrypoint.clone(),
|
||||
config.client_registration_entrypoint.clone(),
|
||||
|
||||
@@ -28,7 +28,7 @@ use mas_router::UrlBuilder;
|
||||
use mas_storage::MIGRATOR;
|
||||
use mas_tasks::TaskQueue;
|
||||
use mas_templates::Templates;
|
||||
use tokio::{io::AsyncRead, signal::unix::SignalKind};
|
||||
use tokio::signal::unix::SignalKind;
|
||||
use tracing::{error, info, log::warn};
|
||||
|
||||
#[derive(Parser, Debug, Default)]
|
||||
@@ -144,19 +144,12 @@ impl Options {
|
||||
|
||||
// Load and compile the WASM policies (and fallback to the default embedded one)
|
||||
info!("Loading and compiling the policy module");
|
||||
let mut policy: Box<dyn AsyncRead + std::marker::Unpin> =
|
||||
if let Some(path) = &config.policy.wasm_module {
|
||||
Box::new(
|
||||
tokio::fs::File::open(path)
|
||||
.await
|
||||
.context("failed to open OPA WASM policy file")?,
|
||||
)
|
||||
} else {
|
||||
Box::new(mas_policy::default_wasm_policy())
|
||||
};
|
||||
let policy_file = tokio::fs::File::open(&config.policy.wasm_module)
|
||||
.await
|
||||
.context("failed to open OPA WASM policy file")?;
|
||||
|
||||
let policy_factory = PolicyFactory::load(
|
||||
&mut policy,
|
||||
policy_file,
|
||||
config.policy.data.clone().unwrap_or_default(),
|
||||
config.policy.register_entrypoint.clone(),
|
||||
config.policy.client_registration_entrypoint.clone(),
|
||||
|
||||
@@ -43,6 +43,26 @@ fn http_address_example_4() -> &'static str {
|
||||
"0.0.0.0:8080"
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "docker"))]
|
||||
fn http_listener_spa_manifest_default() -> Utf8PathBuf {
|
||||
"./frontend/dist/manifest.json".into()
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "docker"))]
|
||||
fn http_listener_spa_assets_default() -> Utf8PathBuf {
|
||||
"./frontend/dist/".into()
|
||||
}
|
||||
|
||||
#[cfg(feature = "docker")]
|
||||
fn http_listener_spa_manifest_default() -> Utf8PathBuf {
|
||||
"/usr/local/share/mas-cli/frontend-manifest.json".into()
|
||||
}
|
||||
|
||||
#[cfg(feature = "docker")]
|
||||
fn http_listener_spa_assets_default() -> Utf8PathBuf {
|
||||
"/usr/local/share/mas-cli/frontend-assets/".into()
|
||||
}
|
||||
|
||||
/// Kind of socket
|
||||
#[derive(Debug, Serialize, Deserialize, JsonSchema, Clone, Copy)]
|
||||
#[serde(rename_all = "lowercase")]
|
||||
@@ -267,11 +287,13 @@ pub enum Resource {
|
||||
|
||||
/// Mount the single page app
|
||||
Spa {
|
||||
/// Path to the vite manifest
|
||||
/// Path to the vite mamanifest.jsonnifest
|
||||
#[serde(default = "http_listener_spa_manifest_default")]
|
||||
#[schemars(with = "String")]
|
||||
manifest: Utf8PathBuf,
|
||||
|
||||
/// Path to the assets to server
|
||||
#[serde(default = "http_listener_spa_assets_default")]
|
||||
#[schemars(with = "String")]
|
||||
assets: Utf8PathBuf,
|
||||
},
|
||||
@@ -325,17 +347,9 @@ impl Default for HttpConfig {
|
||||
Resource::Compat,
|
||||
Resource::GraphQL { playground: true },
|
||||
Resource::Static { web_root: None },
|
||||
#[cfg(not(feature = "docker"))]
|
||||
Resource::Spa {
|
||||
manifest: "./frontend/dist/manifest.json".into(),
|
||||
assets: "./frontend/dist/".into(),
|
||||
},
|
||||
#[cfg(feature = "docker")]
|
||||
Resource::Spa {
|
||||
// This is where the frontend files are mounted in the docker image by
|
||||
// default
|
||||
manifest: "/usr/local/share/mas-cli/frontend-manifest.json".into(),
|
||||
assets: "/usr/local/share/mas-cli/frontend-assets/".into(),
|
||||
manifest: http_listener_spa_manifest_default(),
|
||||
assets: http_listener_spa_assets_default(),
|
||||
},
|
||||
],
|
||||
tls: None,
|
||||
|
||||
@@ -21,6 +21,16 @@ use serde_with::serde_as;
|
||||
|
||||
use super::ConfigurationSection;
|
||||
|
||||
#[cfg(not(feature = "docker"))]
|
||||
fn default_policy_path() -> Utf8PathBuf {
|
||||
"./policies/policy.wasm".into()
|
||||
}
|
||||
|
||||
#[cfg(feature = "docker")]
|
||||
fn default_policy_path() -> Utf8PathBuf {
|
||||
"/usr/local/share/mas-cli/policy.wasm".into()
|
||||
}
|
||||
|
||||
fn default_client_registration_endpoint() -> String {
|
||||
"client_registration/violation".to_owned()
|
||||
}
|
||||
@@ -38,9 +48,9 @@ fn default_authorization_grant_endpoint() -> String {
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
|
||||
pub struct PolicyConfig {
|
||||
/// Path to the WASM module
|
||||
#[serde(default)]
|
||||
#[schemars(with = "Option<String>")]
|
||||
pub wasm_module: Option<Utf8PathBuf>,
|
||||
#[serde(default = "default_policy_path")]
|
||||
#[schemars(with = "String")]
|
||||
pub wasm_module: Utf8PathBuf,
|
||||
|
||||
/// Entrypoint to use when evaluating client registrations
|
||||
#[serde(default = "default_client_registration_endpoint")]
|
||||
@@ -62,7 +72,7 @@ pub struct PolicyConfig {
|
||||
impl Default for PolicyConfig {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
wasm_module: None,
|
||||
wasm_module: default_policy_path(),
|
||||
client_registration_entrypoint: default_client_registration_endpoint(),
|
||||
register_entrypoint: default_register_endpoint(),
|
||||
authorization_grant_entrypoint: default_authorization_grant_endpoint(),
|
||||
|
||||
@@ -376,7 +376,25 @@ async fn test_state(pool: PgPool) -> Result<AppState, anyhow::Error> {
|
||||
let mailer = Mailer::new(&templates, &transport, &mailbox, &mailbox);
|
||||
|
||||
let homeserver = MatrixHomeserver::new("example.com".to_owned());
|
||||
let policy_factory = PolicyFactory::load_default(serde_json::json!({})).await?;
|
||||
|
||||
#[allow(clippy::disallowed_types)]
|
||||
let path = std::path::Path::new(env!("CARGO_MANIFEST_DIR"))
|
||||
.join("..")
|
||||
.join("..")
|
||||
.join("policies")
|
||||
.join("policy.wasm");
|
||||
|
||||
let file = tokio::fs::File::open(path).await?;
|
||||
|
||||
let policy_factory = PolicyFactory::load(
|
||||
file,
|
||||
serde_json::json!({}),
|
||||
"register/violation".to_owned(),
|
||||
"client_registration/violation".to_owned(),
|
||||
"authorization_grant/violation".to_owned(),
|
||||
)
|
||||
.await?;
|
||||
|
||||
let policy_factory = Arc::new(policy_factory);
|
||||
|
||||
let graphql_schema = graphql_schema(&pool);
|
||||
|
||||
@@ -11,12 +11,15 @@ opa-wasm = { git = "https://github.com/matrix-org/rust-opa-wasm.git" }
|
||||
serde = { version = "1.0.147", features = ["derive"] }
|
||||
serde_json = "1.0.88"
|
||||
thiserror = "1.0.37"
|
||||
tokio = { version = "1.21.2", features = ["io-util", "rt"] }
|
||||
tokio = { version = "1.21.2", features = ["io-util"] }
|
||||
tracing = "0.1.37"
|
||||
wasmtime = { version = "2.0.2", default-features = false, features = ["async", "cranelift"] }
|
||||
|
||||
mas-data-model = { path = "../data-model" }
|
||||
oauth2-types = { path = "../oauth2-types" }
|
||||
|
||||
[dev-dependencies]
|
||||
tokio = { version = "1.21.2", features = ["fs", "rt", "macros"] }
|
||||
|
||||
[features]
|
||||
cache = ["wasmtime/cache"]
|
||||
+19
-22
@@ -17,8 +17,6 @@
|
||||
#![warn(clippy::pedantic)]
|
||||
#![allow(clippy::missing_errors_doc)]
|
||||
|
||||
use std::io::Cursor;
|
||||
|
||||
use anyhow::bail;
|
||||
use mas_data_model::{AuthorizationGrant, StorageBackend, User};
|
||||
use oauth2_types::registration::VerifiedClientMetadata;
|
||||
@@ -28,13 +26,6 @@ use thiserror::Error;
|
||||
use tokio::io::{AsyncRead, AsyncReadExt};
|
||||
use wasmtime::{Config, Engine, Module, Store};
|
||||
|
||||
const DEFAULT_POLICY: &[u8] = include_bytes!("../policies/policy.wasm");
|
||||
|
||||
#[must_use]
|
||||
pub fn default_wasm_policy() -> impl AsyncRead + std::marker::Unpin {
|
||||
Cursor::new(DEFAULT_POLICY)
|
||||
}
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum LoadError {
|
||||
#[error("failed to read module")]
|
||||
@@ -115,17 +106,6 @@ impl PolicyFactory {
|
||||
Ok(factory)
|
||||
}
|
||||
|
||||
pub async fn load_default(data: serde_json::Value) -> Result<Self, LoadError> {
|
||||
Self::load(
|
||||
default_wasm_policy(),
|
||||
data,
|
||||
"register/violation".to_owned(),
|
||||
"client_registration/violation".to_owned(),
|
||||
"authorization_grant/violation".to_owned(),
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip(self), err)]
|
||||
pub async fn instantiate(&self) -> Result<Policy, anyhow::Error> {
|
||||
let mut store = Store::new(&self.engine, ());
|
||||
@@ -257,10 +237,27 @@ mod tests {
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_register() {
|
||||
let factory = PolicyFactory::load_default(serde_json::json!({
|
||||
let data = serde_json::json!({
|
||||
"allowed_domains": ["element.io", "*.element.io"],
|
||||
"banned_domains": ["staging.element.io"],
|
||||
}))
|
||||
});
|
||||
|
||||
#[allow(clippy::disallowed_types)]
|
||||
let path = std::path::Path::new(env!("CARGO_MANIFEST_DIR"))
|
||||
.join("..")
|
||||
.join("..")
|
||||
.join("policies")
|
||||
.join("policy.wasm");
|
||||
|
||||
let file = tokio::fs::File::open(path).await.unwrap();
|
||||
|
||||
let factory = PolicyFactory::load(
|
||||
file,
|
||||
data,
|
||||
"register/violation".to_owned(),
|
||||
"client_registration/violation".to_owned(),
|
||||
"authorization_grant/violation".to_owned(),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
|
||||
@@ -135,7 +135,7 @@
|
||||
"client_registration_entrypoint": "client_registration/violation",
|
||||
"data": null,
|
||||
"register_entrypoint": "register/violation",
|
||||
"wasm_module": null
|
||||
"wasm_module": "./policies/policy.wasm"
|
||||
},
|
||||
"allOf": [
|
||||
{
|
||||
@@ -1234,7 +1234,7 @@
|
||||
},
|
||||
"wasm_module": {
|
||||
"description": "Path to the WASM module",
|
||||
"default": null,
|
||||
"default": "./policies/policy.wasm",
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
@@ -1430,17 +1430,17 @@
|
||||
"description": "Mount the single page app",
|
||||
"type": "object",
|
||||
"required": [
|
||||
"assets",
|
||||
"manifest",
|
||||
"name"
|
||||
],
|
||||
"properties": {
|
||||
"assets": {
|
||||
"description": "Path to the assets to server",
|
||||
"default": "./frontend/dist/",
|
||||
"type": "string"
|
||||
},
|
||||
"manifest": {
|
||||
"description": "Path to the vite manifest",
|
||||
"description": "Path to the vite mamanifest.jsonnifest",
|
||||
"default": "./frontend/dist/manifest.json",
|
||||
"type": "string"
|
||||
},
|
||||
"name": {
|
||||
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
Reference in new issue
Block a user