Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Implement config auto-generation and docker volumes #18

Merged
merged 1 commit into from
Nov 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .github/workflows/container.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ jobs:
uses: actions/[email protected]
with:
name: rust
path: artifacts
path: ./identity-server/artifacts

- name: Build Image
id: build-image
Expand All @@ -28,6 +28,7 @@ jobs:
tags: commit-${{ github.sha }} ${{ inputs.additional-tags }}
platforms: linux/arm64,linux/amd64,windows/amd64
oci: true
context: ./identity-server
containerfiles: |
./identity-server/Dockerfile

Expand Down
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
# For local development
.direnv
.envrc
my_config.toml
my-config.toml

# SQLite
*.db
Empty file added identity-server/.empty
Empty file.
23 changes: 15 additions & 8 deletions identity-server/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,25 @@ ARG TARGETPLATFORM

COPY --from=distroless /etc/passwd /etc/passwd
COPY --from=distroless /etc/group /etc/group
USER nonroot
USER nonroot:nonroot
ENV USER=nonroot

ENV XDG_CACHE_HOME=/home/nonroot/.cache
VOLUME ["/home/nonroot/.cache"]
ENV XDG_CACHE_HOME=/var/.cache
# Only here to create the .cache folder
COPY --chmod=644 --chown=nonroot:nonroot .empty /var/.cache/.empty
VOLUME ["/var"]
WORKDIR ["/var"]

ENV XDG_CONFIG_HOME=/etc/cfg
COPY --chmod=644 --chown=nonroot:nonroot ./default-config.toml /etc/cfg/config.toml
VOLUME ["/etc/cfg"]

# Bring in the actual binary we will run
COPY --from=distroless --chmod=544 --chown=nonroot:nonroot /artifacts/$TARGETPLATFORM/identity-server /opt/identity-server
ENTRYPOINT ["/opt/identity-server"]
VOLUME ["/var/db"]
WORKDIR ["/var/db"]

EXPOSE 443/tcp
EXPOSE 80/tcp
EXPOSE 8443/tcp
EXPOSE 8443/udp

ENV RUST_BACKTRACE=1
ENTRYPOINT ["/opt/identity-server"]
CMD ["serve", "--config", "/etc/cfg/config.toml"]
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,16 @@
# Note: When using TLS, we will always send the HSTS header to force clients to only
# use https urls.
[http]
port = 443 # also supports 0 to mean random
port = 8443 # also supports 0 to mean random

# Settings related to configuring TLS certificates. In most cases, the "acme" type is
# the simplest to set up.
[http.tls]
type = "acme" # requires publicly visible port to be 443, otherwise the challenge fails
type = "acme" # publicly visible port MUST be 443, otherwise the challenge fails
domains = [] # You must fill this in with your public domain name(s).
# domains = ["socialvr.net", "socialvr.net:1337", "10.11.12.13"]
is_prod = true # we are using LetsEncrypt's main, production directory.
email = "" # optional: you can fill in your email address here
# domains = ["socialvr.net", "socialvr.net:1337", "10.11.12.13"]

# [http.tls]
# type = "disable" # disables TLS and everything will use HTTP instead.
Expand Down
1 change: 0 additions & 1 deletion identity-server/justfile
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ rust-build:

# Copy artifacts from cargo target dir into to the artifacts directory
artifacts: rust-build
pwd
mkdir -p {{artifacts_dir}}
cp {{target_dir}}/aarch64-apple-darwin/artifact/{{package_name}} {{artifacts_dir}}/{{package_name}}-macos-aarch64
cp {{target_dir}}/x86_64-unknown-linux-musl/artifact/{{package_name}} {{artifacts_dir}}/{{package_name}}-linux-x86_64
Expand Down
43 changes: 37 additions & 6 deletions identity-server/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use std::{path::PathBuf, str::FromStr};

use serde::{Deserialize, Serialize};

pub const DEFAULT_CONFIG_CONTENTS: &str = include_str!("../default_config.toml");
pub const DEFAULT_CONFIG_CONTENTS: &str = include_str!("../default-config.toml");
const CACHE_DIR_SUFFIX: &str = "nexus_identity_server";

#[derive(Serialize, Deserialize, Eq, PartialEq, Debug, Clone)]
Expand Down Expand Up @@ -54,6 +54,17 @@ pub struct HttpConfig {
pub tls: TlsConfig,
}

impl HttpConfig {
fn validate(&self) -> Result<(), ValidationError> {
if let TlsConfig::Acme { ref domains, .. } = self.tls {
if domains.is_empty() {
return Err(ValidationError::UnspecifiedDomain);
}
}
Ok(())
}
}

impl Default for HttpConfig {
fn default() -> Self {
Self {
Expand All @@ -65,7 +76,7 @@ impl Default for HttpConfig {

impl HttpConfig {
const fn default_port() -> u16 {
443
8443
}
}

Expand Down Expand Up @@ -131,10 +142,18 @@ fn default_some<T: Default>() -> Option<T> {
Some(T::default())
}

#[derive(Debug, thiserror::Error)]
#[derive(Debug, thiserror::Error, Eq, PartialEq)]
pub enum ConfigError {
#[error("error in toml file: {0}")]
#[error("error deserializing toml file: {0}")]
Toml(#[from] toml::de::Error),
#[error("config file was invalid: {0}")]
FailedValidation(#[from] ValidationError),
}

#[derive(Debug, thiserror::Error, Eq, PartialEq)]
pub enum ValidationError {
#[error("when using ACME tls, you *must* specify at least one domain")]
UnspecifiedDomain,
}

/// The contents of the config file. Contains all settings customizeable during
Expand All @@ -152,6 +171,14 @@ pub struct Config {
pub third_party: ThirdPartySettings,
}

impl Config {
/// Validates the deserialized config
pub fn validate(&self) -> Result<(), ValidationError> {
self.http.validate()?;
Ok(())
}
}

impl FromStr for Config {
type Err = ConfigError;

Expand All @@ -173,7 +200,7 @@ mod test {
db_file: PathBuf::from("./identities.db"),
},
http: HttpConfig {
port: 443,
port: 8443,
tls: TlsConfig::Acme {
email: String::new(),
domains: Vec::new(),
Expand All @@ -197,10 +224,14 @@ mod test {
}

#[test]
fn test_default_config_deserializes_correctly() {
fn test_default_config_deserializes_correctly_but_fails_validation() {
let deserialized: Config = toml::from_str(DEFAULT_CONFIG_CONTENTS)
.expect("default config file should always deserialize");
assert_eq!(deserialized, Config::default());
assert_eq!(
deserialized.validate(),
Err(ValidationError::UnspecifiedDomain)
)
}

#[test]
Expand Down
Loading