5 Commits

Author SHA1 Message Date
3c29377013 Trigger reconcile webhook once build is done
All checks were successful
Build and deploy / build (push) Successful in 7m18s
2025-04-23 21:00:02 +02:00
07123a92a9 Use reusable workflow
All checks were successful
Build and deploy / build (push) Successful in 5m30s
2025-04-23 14:08:42 +02:00
ac15ce1d38 Clarified password env variable missing error
All checks were successful
kustomization/siranga/3850ce12 reconciliation succeeded
Build and deploy / Build container and manifests (push) Successful in 5m49s
2025-04-22 10:47:18 +02:00
5a7652f3a4 Make ldap search filter configurable
All checks were successful
Build and deploy / Build container and manifests (push) Successful in 6m8s
kustomization/siranga/3850ce12 reconciliation succeeded
2025-04-22 00:42:56 +02:00
95ad229077 Get bind_dn from secret 2025-04-22 00:42:33 +02:00
5 changed files with 77 additions and 83 deletions

View File

@@ -7,83 +7,9 @@ on:
tags:
- v*.*.*
env:
OCI_REPO: git.huizinga.dev/dreaded_x/${{ gitea.event.repository.name}}
jobs:
build:
name: Build container and manifests
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Set timestamp and release version
run: |
echo "TIMESTAMP=$(git log -1 --pretty=%ct)" >> $GITHUB_ENV
git fetch --prune --unshallow --tags --force
echo "RELEASE_VERSION=$(git describe --always --dirty='--modified')" >> $GITHUB_ENV
cat $GITHUB_ENV
- name: Login to registry
uses: docker/login-action@v3
with:
registry: git.huizinga.dev
username: ${{ gitea.actor }}
password: ${{ secrets.REGISTRY_TOKEN }}
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Install kustomize
run: |
curl -s "https://raw.githubusercontent.com/kubernetes-sigs/kustomize/master/hack/install_kustomize.sh" | bash
- name: Setup Flux CLI
uses: https://github.com/fluxcd/flux2/action@main
with:
version: v2.5.0
- name: Docker meta
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.OCI_REPO }}
tags: |
type=edge
type=ref,event=branch
type=semver,pattern=v{{version}}
type=semver,pattern=v{{major}}.{{minor}}
type=semver,pattern=v{{major}}
- name: Build container
id: build
uses: docker/build-push-action@v6
with:
context: .
push: true
sbom: true
provenance: mode=max
tags: ${{ steps.meta.outputs.tags }}
annotations: ${{ steps.meta.outputs.annotations }}
cache-from: type=gha
cache-to: type=gha,mode=max
build-args: |
"RELEASE_VERSION=${{ env.RELEASE_VERSION }}"
env:
SOURCE_DATE_EPOCH: ${{ env.TIMESTAMP }}
- name: Kustomize manifests
run: |
./kustomize build ./manifests | sed "s/\${DIGEST}/${{ steps.build.outputs.digest }}/" > ./manifests.yaml
- name: Push manifests
run: |
flux push artifact oci://${{ env.OCI_REPO }}/manifests:${{ gitea.head_ref || gitea.ref_name }} \
--path="./manifests.yaml" \
--source="$(git config --get remote.origin.url)" \
--revision="$(git rev-parse HEAD)" \
$(echo "${{ steps.meta.outputs.labels }}" | sed -e 's/^/-a /')
flux tag artifact oci://${{ env.OCI_REPO }}/manifests:${{ gitea.head_ref || gitea.ref_name }} \
$(echo "${{ steps.meta.outputs.tags }}" | sed -e 's/^.*:/--tag /')
uses: dreaded_x/workflows/.gitea/workflows/rust-kubernetes.yaml@66ab50c3ac239dbdd1e42e6276ec2e65b6a79379
with:
webhook_url: ${{ secrets.WEBHOOK_URL }}
secrets: inherit

34
Cargo.lock generated
View File

@@ -1684,6 +1684,16 @@ dependencies = [
"url",
]
[[package]]
name = "leon"
version = "3.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "42a865ffec5587961f5afc6d365bccb304f4feaa1928f4fe94c91c9d210d7310"
dependencies = [
"miette",
"thiserror 2.0.12",
]
[[package]]
name = "libc"
version = "0.2.172"
@@ -1772,6 +1782,29 @@ version = "2.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
[[package]]
name = "miette"
version = "7.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a955165f87b37fd1862df2a59547ac542c77ef6d17c666f619d1ad22dd89484"
dependencies = [
"cfg-if",
"miette-derive",
"thiserror 1.0.69",
"unicode-width 0.1.14",
]
[[package]]
name = "miette-derive"
version = "7.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bf45bf44ab49be92fd1227a3be6fc6f617f1a337c06af54981048574d8783147"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "mime"
version = "0.3.17"
@@ -2945,6 +2978,7 @@ dependencies = [
"hyper",
"hyper-util",
"ldap3",
"leon",
"pin-project-lite",
"rand 0.8.5",
"ratatui",

View File

@@ -18,6 +18,7 @@ http-body-util = { version = "0.1.3", features = ["full"] }
hyper = { version = "1.6.0", features = ["full"] }
hyper-util = { version = "0.1.11", features = ["full"] }
ldap3 = "0.11.5"
leon = "3.0.2"
pin-project-lite = "0.2.16"
rand = "0.8.5"
ratatui = { version = "0.29.0", features = ["unstable-backend-writer"] }

View File

@@ -55,8 +55,13 @@ spec:
value: ldap://lldap.lldap.svc.cluster.local:3890
- name: LDAP_BASE
value: ou=people,dc=huizinga,dc=dev
- name: LDAP_SEARCH_FILTER
value: (uid={username})
- name: LDAP_BIND_DN
value: uid=siranga.siranga,ou=people,dc=huizinga,dc=dev
valueFrom:
secretKeyRef:
name: siranga-lldap-credentials
key: bind_dn
- name: LDAP_PASSWORD_FILE
value: /secrets/credentials/password
- name: PRIVATE_KEY_FILE

View File

@@ -1,4 +1,5 @@
use ldap3::{LdapConnAsync, SearchEntry};
use leon::{Template, vals};
use russh::keys::PublicKey;
use tokio::select;
use tokio::task::JoinHandle;
@@ -9,6 +10,7 @@ use tracing::{debug, error};
pub struct Ldap {
base: String,
ldap: ldap3::Ldap,
search_filter: String,
}
#[derive(Debug, thiserror::Error)]
@@ -21,6 +23,10 @@ pub enum LdapError {
MissingEnvironmentVariable(&'static str),
#[error("Could not read password file: {0}")]
CouldNotReadPasswordFile(#[from] std::io::Error),
#[error("Failed to parse search filter: {0}")]
FailedToParseSearchFilter(#[from] leon::ParseError),
#[error("Failed to render search filter: {0}")]
FailedToRenderSearchFilter(#[from] leon::RenderError),
}
impl Ldap {
@@ -33,11 +39,14 @@ impl Ldap {
.map_err(|_| LdapError::MissingEnvironmentVariable("LDAP_BASE"))?;
let bind_dn = std::env::var("LDAP_BIND_DN")
.map_err(|_| LdapError::MissingEnvironmentVariable("LDAP_BIND_DN"))?;
let search_filter = std::env::var("LDAP_SEARCH_FILTER")
.map_err(|_| LdapError::MissingEnvironmentVariable("LDAP_SEARCH_FILTER"))?;
let password = std::env::var("LDAP_PASSWORD_FILE").map_or_else(
|_| {
std::env::var("LDAP_PASSWORD")
.map_err(|_| LdapError::MissingEnvironmentVariable("LDAP_PASSWORD"))
std::env::var("LDAP_PASSWORD").map_err(|_| {
LdapError::MissingEnvironmentVariable("LDAP_PASSWORD or LDAP_PASSWORD_FILE")
})
},
|path| {
std::fs::read_to_string(path)
@@ -65,20 +74,39 @@ impl Ldap {
ldap.simple_bind(&bind_dn, &password).await?.success()?;
Ok((Self { base, ldap }, handle))
Ok((
Self {
base,
ldap,
search_filter,
},
handle,
))
}
pub async fn get_ssh_keys(
&mut self,
user: impl AsRef<str>,
) -> Result<Vec<PublicKey>, LdapError> {
let search_filter = Template::parse(&self.search_filter)?;
let search_filter = search_filter.render(&&vals(|key| {
if key == "username" {
Some(user.as_ref().to_string().into())
} else {
None
}
}))?;
debug!("search_filter = {search_filter}");
Ok(self
.ldap
.search(
&self.base,
ldap3::Scope::Subtree,
// TODO: Make this not hardcoded
&format!("(uid={})", user.as_ref()),
&search_filter,
vec!["sshkeys"],
)
.await?