Compare commits

..

21 Commits

Author SHA1 Message Date
mbecker20
e029e94f0d 1.15.2 Pass KOMODO_OIDC_ADDITIONAL_AUDIENCES 2024-10-07 15:44:51 -04:00
mbecker20
3be2b5163b 1.15.1 do not add trailing slash OIDC provider 2024-10-07 13:23:40 -04:00
mbecker20
6a145f58ff pass provider as-is. Authentik users should add a trailing slash 2024-10-07 13:16:25 -04:00
mbecker20
f1cede2ebd update dark / light stack screenshot to have action buttons 2024-10-07 08:05:39 -04:00
mbecker20
a5cfa1d412 update screenshots 2024-10-07 07:30:18 -04:00
mbecker20
a0674654c1 update screenshots 2024-10-07 07:30:11 -04:00
mbecker20
3faa1c58c1 update screenshots 2024-10-07 07:30:05 -04:00
mbecker20
7e296f34af screenshots 2024-10-07 07:29:58 -04:00
mbecker20
9f8ced190c update screenshots 2024-10-07 07:29:02 -04:00
mbecker20
c194bb16d8 update screenshots 2024-10-07 07:28:45 -04:00
mbecker20
39fec9b55e update screenshots 2024-10-07 07:27:52 -04:00
mbecker20
e97ed9888d update screenshots 1 2024-10-07 07:27:16 -04:00
mbecker20
559102ffe3 update readme 2024-10-07 07:25:36 -04:00
mbecker20
6bf80ddcc7 update screenshots readme 2024-10-07 07:25:24 -04:00
mbecker20
89dbe1b4d9 stack file_contents editor respects readOnly / disabled 2024-10-07 06:58:00 -04:00
mbecker20
334e16d646 OIDC use preferred username 2024-10-07 06:35:46 -04:00
mbecker20
a7bbe519f4 add build server link 2024-10-07 06:15:53 -04:00
mbecker20
5827486c5a add redirect uri for OIDC 2024-10-07 06:15:00 -04:00
mbecker20
8ca8f7eddd add context to oidc init error 2024-10-07 06:10:12 -04:00
mbecker20
0600276b43 fix parse KOMODO_MONGO_ in envs 2024-10-07 05:43:09 -04:00
mbecker20
a77a1495c7 active resources mb-12 not always there 2024-10-07 05:14:54 -04:00
42 changed files with 142 additions and 95 deletions

26
Cargo.lock generated
View File

@@ -41,7 +41,7 @@ dependencies = [
[[package]]
name = "alerter"
version = "1.15.0"
version = "1.15.2"
dependencies = [
"anyhow",
"axum",
@@ -943,7 +943,7 @@ dependencies = [
[[package]]
name = "command"
version = "1.15.0"
version = "1.15.2"
dependencies = [
"komodo_client",
"run_command",
@@ -1355,7 +1355,7 @@ dependencies = [
[[package]]
name = "environment_file"
version = "1.15.0"
version = "1.15.2"
dependencies = [
"thiserror",
]
@@ -1439,7 +1439,7 @@ dependencies = [
[[package]]
name = "formatting"
version = "1.15.0"
version = "1.15.2"
dependencies = [
"serror",
]
@@ -1571,7 +1571,7 @@ checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd"
[[package]]
name = "git"
version = "1.15.0"
version = "1.15.2"
dependencies = [
"anyhow",
"command",
@@ -2192,7 +2192,7 @@ dependencies = [
[[package]]
name = "komodo_cli"
version = "1.15.0"
version = "1.15.2"
dependencies = [
"anyhow",
"clap",
@@ -2208,7 +2208,7 @@ dependencies = [
[[package]]
name = "komodo_client"
version = "1.15.0"
version = "1.15.2"
dependencies = [
"anyhow",
"async_timing_util",
@@ -2239,7 +2239,7 @@ dependencies = [
[[package]]
name = "komodo_core"
version = "1.15.0"
version = "1.15.2"
dependencies = [
"anyhow",
"async_timing_util",
@@ -2296,7 +2296,7 @@ dependencies = [
[[package]]
name = "komodo_periphery"
version = "1.15.0"
version = "1.15.2"
dependencies = [
"anyhow",
"async_timing_util",
@@ -2382,7 +2382,7 @@ dependencies = [
[[package]]
name = "logger"
version = "1.15.0"
version = "1.15.2"
dependencies = [
"anyhow",
"komodo_client",
@@ -2446,7 +2446,7 @@ dependencies = [
[[package]]
name = "migrator"
version = "1.15.0"
version = "1.15.2"
dependencies = [
"anyhow",
"dotenvy",
@@ -3101,7 +3101,7 @@ checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e"
[[package]]
name = "periphery_client"
version = "1.15.0"
version = "1.15.2"
dependencies = [
"anyhow",
"komodo_client",
@@ -4879,7 +4879,7 @@ checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1"
[[package]]
name = "update_logger"
version = "1.15.0"
version = "1.15.2"
dependencies = [
"anyhow",
"komodo_client",

View File

@@ -3,7 +3,7 @@ resolver = "2"
members = ["bin/*", "lib/*", "client/core/rs", "client/periphery/rs"]
[workspace.package]
version = "1.15.0"
version = "1.15.2"
edition = "2021"
authors = ["mbecker20 <becker.maxh@gmail.com>"]
license = "GPL-3.0-or-later"

View File

@@ -32,17 +32,15 @@ pub async fn init_default_oidc_client() {
return;
}
async {
let provider = config.oidc_provider.to_string();
// Use OpenID Connect Discovery to fetch the provider metadata.
let provider_metadata = CoreProviderMetadata::discover_async(
IssuerUrl::new(if provider.ends_with('/') {
provider
} else {
provider + "/"
})?,
IssuerUrl::new(config.oidc_provider.clone())?,
async_http_client,
)
.await?;
.await
.context(
"Failed to get OIDC /.well-known/openid-configuration",
)?;
// Create an OpenID Connect client by specifying the client ID, client secret, authorization URL
// and token URL.

View File

@@ -135,7 +135,9 @@ async fn callback(
.context("CSRF Token invalid")?;
if komodo_timestamp() > valid_until {
return Err(anyhow!("CSRF token invalid (Timed out). The token must be "));
return Err(anyhow!(
"CSRF token invalid (Timed out). The token must be "
));
}
let token_response = client
@@ -150,8 +152,21 @@ async fn callback(
let id_token = token_response
.id_token()
.context("OIDC Server did not return an ID token")?;
// Some providers attach additional audiences, they must be added here
// so token verification succeeds.
let verifier = client.id_token_verifier();
let additional_audiences = &core_config().oidc_additional_audiences;
let verifier = if additional_audiences.is_empty() {
verifier
} else {
verifier.set_other_audience_verifier_fn(|aud| {
additional_audiences.contains(aud)
})
};
let claims = id_token
.claims(&client.id_token_verifier(), &nonce)
.claims(&verifier, &nonce)
.context("Failed to verify token claims")?;
// Verify the access token hash to ensure that the access token hasn't been substituted for
@@ -191,20 +206,25 @@ async fn callback(
if !no_users_exist && core_config.disable_user_registration {
return Err(anyhow!("User registration is disabled"));
}
// Email will use user_id if it isn't available.
let email = claims
.email()
.map(|email| email.as_str())
.unwrap_or(user_id);
let username = if core_config.oidc_use_full_email {
email
} else {
email
.split_once('@')
.map(|(username, _)| username)
.unwrap_or(email)
}
.to_string();
// Will use preferred_username, then email, then user_id if it isn't available.
let username = claims
.preferred_username()
.map(|username| username.to_string())
.unwrap_or_else(|| {
let email = claims
.email()
.map(|email| email.as_str())
.unwrap_or(user_id);
if core_config.oidc_use_full_email {
email
} else {
email
.split_once('@')
.map(|(username, _)| username)
.unwrap_or(email)
}
.to_string()
});
let user = User {
id: Default::default(),
username,

View File

@@ -87,6 +87,9 @@ pub fn core_config() -> &'static CoreConfig {
.unwrap_or(config.oidc_client_secret),
oidc_use_full_email: env.komodo_oidc_use_full_email
.unwrap_or(config.oidc_use_full_email),
oidc_additional_audiences: maybe_read_list_from_file(env.komodo_oidc_additional_audiences_file,env
.komodo_oidc_additional_audiences)
.unwrap_or(config.oidc_additional_audiences),
google_oauth: OauthCredentials {
enabled: env
.komodo_google_oauth_enabled

View File

@@ -116,6 +116,10 @@ pub struct Env {
pub komodo_oidc_client_secret_file: Option<PathBuf>,
/// Override `oidc_use_full_email`
pub komodo_oidc_use_full_email: Option<bool>,
/// Override `oidc_additional_audiences`
pub komodo_oidc_additional_audiences: Option<Vec<String>>,
/// Override `oidc_additional_audiences` from file
pub komodo_oidc_additional_audiences_file: Option<PathBuf>,
/// Override `google_oauth.enabled`
pub komodo_google_oauth_enabled: Option<bool>,
@@ -159,31 +163,31 @@ pub struct Env {
pub komodo_github_webhook_app_pk_path: Option<String>,
/// Override `database.uri`
#[serde(alias = "KOMODO_MONGO_URI")]
#[serde(alias = "komodo_mongo_uri")]
pub komodo_database_uri: Option<String>,
/// Override `database.uri` from file
#[serde(alias = "KOMODO_MONGO_URI_FILE")]
#[serde(alias = "komodo_mongo_uri_file")]
pub komodo_database_uri_file: Option<PathBuf>,
/// Override `database.address`
#[serde(alias = "KOMODO_MONGO_ADDRESS")]
#[serde(alias = "komodo_mongo_address")]
pub komodo_database_address: Option<String>,
/// Override `database.username`
#[serde(alias = "KOMODO_MONGO_USERNAME")]
#[serde(alias = "komodo_mongo_username")]
pub komodo_database_username: Option<String>,
/// Override `database.username` with file
#[serde(alias = "KOMODO_MONGO_USERNAME_FILE")]
#[serde(alias = "komodo_mongo_username_file")]
pub komodo_database_username_file: Option<PathBuf>,
/// Override `database.password`
#[serde(alias = "KOMODO_MONGO_PASSWORD")]
#[serde(alias = "komodo_mongo_password")]
pub komodo_database_password: Option<String>,
/// Override `database.password` with file
#[serde(alias = "KOMODO_MONGO_PASSWORD_FILE")]
#[serde(alias = "komodo_mongo_password_file")]
pub komodo_database_password_file: Option<PathBuf>,
/// Override `database.app_name`
#[serde(alias = "KOMODO_MONGO_APP_NAME")]
#[serde(alias = "komodo_mongo_app_name")]
pub komodo_database_app_name: Option<String>,
/// Override `database.db_name`
#[serde(alias = "KOMODO_MONGO_DB_NAME")]
#[serde(alias = "komodo_mongo_db_name")]
pub komodo_database_db_name: Option<String>,
/// Override `aws.access_key_id`
@@ -344,6 +348,11 @@ pub struct CoreConfig {
#[serde(default)]
pub oidc_use_full_email: bool,
/// Your OIDC provider may set additional audiences other than `client_id`,
/// they must be added here to make claims verification work.
#[serde(default)]
pub oidc_additional_audiences: Vec<String>,
// =========
// = Oauth =
// =========
@@ -548,6 +557,11 @@ impl CoreConfig {
&config.oidc_client_secret,
),
oidc_use_full_email: config.oidc_use_full_email,
oidc_additional_audiences: config
.oidc_additional_audiences
.iter()
.map(|aud| empty_or_redacted(aud))
.collect(),
google_oauth: OauthCredentials {
enabled: config.google_oauth.enabled,
id: empty_or_redacted(&config.google_oauth.id),

View File

@@ -82,6 +82,9 @@ KOMODO_OIDC_ENABLED=false
# KOMODO_OIDC_CLIENT_SECRET= # Alt: KOMODO_OIDC_CLIENT_SECRET_FILE
## Make usernames the full email.
# KOMODO_OIDC_USE_FULL_EMAIL=true
## Add additional trusted audiences for token claims verification.
## Supports comma separated list, and passing with _FILE (for compose secrets).
# KOMODO_OIDC_ADDITIONAL_AUDIENCES=abc,123 # Alt: KOMODO_OIDC_ADDITIONAL_AUDIENCES_FILE
## Github Oauth
KOMODO_GITHUB_OAUTH_ENABLED=false

View File

@@ -161,10 +161,17 @@ oidc_client_secret = ""
## If true, use the full email for usernames.
## Otherwise, the @address will be stripped,
## making usernames more concise.
## Default: false.
## Env: KOMODO_OIDC_USE_FULL_EMAIL
## Default: false.
oidc_use_full_email = false
## Some providers attach other audiences in addition to the client_id.
## If you have this issue, `Invalid audiences: `...` is not a trusted audience"`,
## you can add the audience `...` to the list here (assuming it should be trusted).
## Env: KOMODO_OIDC_ADDITIONAL_AUDIENCES or KOMODO_OIDC_ADDITIONAL_AUDIENCES_FILE
## Default: empty
oidc_additional_audiences = []
#########
# OAUTH #
#########

View File

@@ -1,15 +1,18 @@
# Advanced Configuration
### Oauth2
### OIDC / Oauth2
To enable OAuth2 login, you must create a client on the respective OAuth provider,
for example [Github](https://docs.github.com/en/apps/oauth-apps/building-oauth-apps/creating-an-oauth-app)
or [Google](https://developers.google.com/identity/protocols/oauth2).
Komodo also supports self hosted Oauth2 providers like [Authentik](https://docs.goauthentik.io/docs/providers/oauth2/) or [Gitea](https://docs.gitea.com/development/oauth2-provider).
- Komodo uses the `web application` login flow.
- The redirect uri is:
- `<KOMODO_HOST>/auth/github/callback` for Github.
- `<KOMODO_HOST>/auth/google/callback` for Google.
- `<KOMODO_HOST>/auth/oidc/callback` for OIDC.
### Mount a config file

View File

@@ -693,6 +693,7 @@ export const StackConfig = ({
}
onValueChange={(file_contents) => set({ file_contents })}
language="yaml"
readOnly={disabled}
/>
);
},

View File

@@ -27,9 +27,7 @@ export const Dashboard = () => {
return (
<>
<div className="mb-12">
<ActiveResources />
</div>
<ActiveResources />
<Page
title="Dashboard"
icon={<Box className="w-8 h-8" />}
@@ -253,37 +251,39 @@ const ActiveResources = () => {
if (resources.length === 0) return null;
return (
<Section
title="Active"
icon={
<Circle className="w-4 h-4 stroke-none transition-colors fill-green-500" />
}
>
<DataTable
tableKey="active-resources"
data={resources}
columns={[
{
accessorKey: "name",
header: ({ column }) => (
<SortableHeader column={column} title="Name" />
),
cell: ({ row }) => (
<ResourceLink type={row.original.type} id={row.original.id} />
),
},
{
accessorKey: "type",
header: ({ column }) => (
<SortableHeader column={column} title="Resource" />
),
},
{
header: "State",
cell: ({ row }) => row.original.state,
},
]}
/>
</Section>
<div className="mb-12">
<Section
title="Active"
icon={
<Circle className="w-4 h-4 stroke-none transition-colors fill-green-500" />
}
>
<DataTable
tableKey="active-resources"
data={resources}
columns={[
{
accessorKey: "name",
header: ({ column }) => (
<SortableHeader column={column} title="Name" />
),
cell: ({ row }) => (
<ResourceLink type={row.original.type} id={row.original.id} />
),
},
{
accessorKey: "type",
header: ({ column }) => (
<SortableHeader column={column} title="Resource" />
),
},
{
header: "State",
cell: ({ row }) => row.original.state,
},
]}
/>
</Section>
</div>
);
};

View File

@@ -6,6 +6,8 @@ A tool to build and deploy software across many servers.
🦎 [Try the Demo](https://demo.komo.do)
🦎 [See the Build Server](https://build.komo.do)
🦎 [Join the Discord](https://discord.gg/DRqE8Fvg5c)
## About
@@ -31,25 +33,21 @@ there are no warranties. Use at your own risk.
### Light Theme
![Dashboard](https://raw.githubusercontent.com/mbecker20/komodo/main/screenshots/Light-Dashboard.png)
![Resources](https://raw.githubusercontent.com/mbecker20/komodo/main/screenshots/Light-Resources.png)
![Deployment](https://raw.githubusercontent.com/mbecker20/komodo/main/screenshots/Light-Deployment.png)
![Server](https://raw.githubusercontent.com/mbecker20/komodo/main/screenshots/Light-Server.png)
![Stack](https://raw.githubusercontent.com/mbecker20/komodo/main/screenshots/Light-Stack.png)
![Compose](https://raw.githubusercontent.com/mbecker20/komodo/main/screenshots/Light-Compose.png)
![Env](https://raw.githubusercontent.com/mbecker20/komodo/main/screenshots/Light-Env.png)
![Sync](https://raw.githubusercontent.com/mbecker20/komodo/main/screenshots/Light-Sync.png)
![Procedure](https://raw.githubusercontent.com/mbecker20/komodo/main/screenshots/Light-Procedure.png)
![UserGroup](https://raw.githubusercontent.com/mbecker20/komodo/main/screenshots/Light-UserGroup.png)
![Update](https://raw.githubusercontent.com/mbecker20/komodo/main/screenshots/Light-Update.png)
![Search](https://raw.githubusercontent.com/mbecker20/komodo/main/screenshots/Light-Search.png)
![Stats](https://raw.githubusercontent.com/mbecker20/komodo/main/screenshots/Light-Stats.png)
![Export](https://raw.githubusercontent.com/mbecker20/komodo/main/screenshots/Light-Export.png)
### Dark Theme
![Dashboard](https://raw.githubusercontent.com/mbecker20/komodo/main/screenshots/Dark-Dashboard.png)
![Resources](https://raw.githubusercontent.com/mbecker20/komodo/main/screenshots/Dark-Resources.png)
![Deployment](https://raw.githubusercontent.com/mbecker20/komodo/main/screenshots/Dark-Deployment.png)
![Server](https://raw.githubusercontent.com/mbecker20/komodo/main/screenshots/Dark-Server.png)
![Stack](https://raw.githubusercontent.com/mbecker20/komodo/main/screenshots/Dark-Stack.png)
![Compose](https://raw.githubusercontent.com/mbecker20/komodo/main/screenshots/Dark-Compose.png)
![Env](https://raw.githubusercontent.com/mbecker20/komodo/main/screenshots/Dark-Env.png)
![Sync](https://raw.githubusercontent.com/mbecker20/komodo/main/screenshots/Dark-Sync.png)
![Procedure](https://raw.githubusercontent.com/mbecker20/komodo/main/screenshots/Dark-Procedure.png)
![UserGroup](https://raw.githubusercontent.com/mbecker20/komodo/main/screenshots/Dark-UserGroup.png)
![Update](https://raw.githubusercontent.com/mbecker20/komodo/main/screenshots/Dark-Update.png)
![Search](https://raw.githubusercontent.com/mbecker20/komodo/main/screenshots/Dark-Search.png)
![Stats](https://raw.githubusercontent.com/mbecker20/komodo/main/screenshots/Dark-Stats.png)
![Export](https://raw.githubusercontent.com/mbecker20/komodo/main/screenshots/Dark-Export.png)

Binary file not shown.

After

Width:  |  Height:  |  Size: 572 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 152 KiB

After

Width:  |  Height:  |  Size: 368 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 213 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 197 KiB

BIN
screenshots/Dark-Env.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 434 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 223 KiB

After

Width:  |  Height:  |  Size: 487 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 145 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 156 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 151 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 140 KiB

BIN
screenshots/Dark-Stack.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 405 KiB

BIN
screenshots/Dark-Stats.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 405 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 145 KiB

After

Width:  |  Height:  |  Size: 476 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 182 KiB

After

Width:  |  Height:  |  Size: 451 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 133 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 580 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 149 KiB

After

Width:  |  Height:  |  Size: 375 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 151 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 182 KiB

BIN
screenshots/Light-Env.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 434 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 176 KiB

After

Width:  |  Height:  |  Size: 495 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 150 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 157 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 138 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 146 KiB

BIN
screenshots/Light-Stack.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 416 KiB

BIN
screenshots/Light-Stats.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 402 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 175 KiB

After

Width:  |  Height:  |  Size: 409 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 186 KiB

After

Width:  |  Height:  |  Size: 461 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 140 KiB