Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
cargo.toml update
  • Loading branch information
Kerwood committed Jul 7, 2024
0 parents commit cbab9be
Show file tree
Hide file tree
Showing 28 changed files with 1,232 additions and 0 deletions.
14 changes: 14 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# top-most EditorConfig file
root = true

[*.rs]
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
indent_style = space
indent_size = 4

[*.md]
indent_style = space
indent_size = 2
trim_trailing_whitespace = false
7 changes: 7 additions & 0 deletions .env-example
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Copy/rename this file to ".env" and the Justfile will pick up the environment variables.

AZURE_TENANT_ID=
AZURE_CLIENT_ID=
AZURE_CLIENT_SECRET=
RECONCILE_TIME=10
RETRY_TIME=5
70 changes: 70 additions & 0 deletions .github/workflows/build-n-release.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
name: Build and Release

on:
push:
branches:
- "!*"
tags:
- "v*"

env:
CARGO_TERM_COLOR: always
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}

jobs:
rustfmt:
name: Rustfmt
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- run: rustup component add rustfmt
- run: cargo fmt -- --check

build-and-push-image:
name: Build OCI image and push
needs: rustfmt
runs-on: ubuntu-latest
permissions:
contents: read
packages: write

steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Login to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Extract metadata (tags, labels) for Docker
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}

- name: Build and push Docker image
uses: docker/build-push-action@v6
with:
context: .
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: |
org.opencontainers.image.source=https://github.com/${{ github.repository }}
create-release:
name: Create Release
needs: build-and-push-image
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- uses: actions/checkout@v4
- uses: ncipollo/release-action@v1
with:
body: "Image name: `ghcr.io/${{ github.repository }}:${{ github.ref_name }}`"
generateReleaseNotes: true
makeLatest: true
24 changes: 24 additions & 0 deletions .github/workflows/trigger-chart-build.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
name: Chart Releaser

on:
push:
branches:
- main
paths:
- "chart/Chart.yaml"

jobs:
trigger-workflow:
name: Trigger Chart Workflow
runs-on: ubuntu-latest

steps:
- uses: convictional/[email protected]
with:
owner: kerwood
repo: helm-charts
github_token: ${{ secrets.WORKFLOW_PAT }}
workflow_file_name: chart-releaser.yaml
propagate_failure: true
trigger_workflow: true
wait_workflow: true
26 changes: 26 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# Created by https://www.toptal.com/developers/gitignore/api/dotenv,rust
# Edit at https://www.toptal.com/developers/gitignore?templates=dotenv,rust

### kubectl ###
kubeconfig

### dotenv ###
.env

### Rust ###
# Generated by Cargo
# will have compiled files and executables
debug/
target/

# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html
Cargo.lock

# These are backup files generated by rustfmt
**/*.rs.bk

# MSVC Windows builds of rustc generate these, which store debugging information
*.pdb

# End of https://www.toptal.com/developers/gitignore/api/dotenv,rust
7 changes: 7 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
[workspace]
resolver = "2"
members = [
"az_group_crd",
"az_group_manager_crd",
"az_group_manager",
]
50 changes: 50 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
###################################################################################
## Builder
###################################################################################
FROM rust:alpine3.20 AS builder

ENV OPENSSL_STATIC=1

# RUN rustup target add x86_64-unknown-linux-musl
# RUN apt update && apt install -y musl-tools musl-dev pkg-config libssl-dev upx make
RUN apk update && apk add --no-cache musl-dev openssl-dev openssl-libs-static upx
RUN update-ca-certificates

# Create appuser
ENV USER=rust
ENV UID=1001

RUN adduser \
--disabled-password \
--gecos "" \
--home "/" \
--shell "/sbin/nologin" \
--no-create-home \
--uid "${UID}" \
"${USER}"


WORKDIR /workdir

COPY ./ .

RUN cargo build --target x86_64-unknown-linux-musl --release
RUN upx --best --lzma target/x86_64-unknown-linux-musl/release/az-group-manager

###################################################################################
## Final image
###################################################################################
FROM scratch

WORKDIR /

# Copy from builder.
COPY --from=builder /etc/passwd /etc/passwd
COPY --from=builder /etc/group /etc/group
COPY --from=builder /etc/ssl/certs /etc/ssl/certs
COPY --from=builder /workdir/target/x86_64-unknown-linux-musl/release/az-group-manager/ /

# Use an unprivileged user.
USER 1001:1001

ENTRYPOINT ["./az-group-manager"]
34 changes: 34 additions & 0 deletions Justfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
set dotenv-load
cluster_name := "azure-group-controller"

[private]
default:
@just --list

# Create a .env file to use for local development.
create-dot-env:
cat .env-example >> .env

# Cargo run with needed parameters
run:
cargo run serve -t $AZURE_TENANT_ID -i $AZURE_CLIENT_ID -s $AZURE_CLIENT_SECRET -b $RECONCILE_TIME -r $RETRY_TIME

# Bring up the Kind cluster
cluster-up:
kind create cluster --name {{cluster_name}} --image kindest/node:v1.30.2
sleep "10"
kubectl wait --namespace kube-system --for=condition=ready pod --selector="tier=control-plane" --timeout=180s

# Bring down the Kind cluster
cluster-down:
kind delete cluster --name {{cluster_name}}
-rm ./kubeconfig

# Apply AzureGroup and AzureGroupManager CRDs
crds-apply:
cargo run -p az-group-manager -- print-crd | kubectl apply -f -

# Delete AzureGroup and AzureGroupManager CRDs
crds-delete:
kubectl delete crd azuregroupmanagers.kerwood.github.com azuregroups.kerwood.github.com

123 changes: 123 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
# Azure Group Controller

[![forthebadge made-with-rust](http://ForTheBadge.com/images/badges/made-with-rust.svg)](https://www.rust-lang.org/)

A Kubernetes controller that creates a `AzureGroup` resource with a list of members and some basic information on the group.
The controller will continuously reonconsile the `AzureGroup` resource.

## Prerequisites

For deploying:

- Helm, <https://helm.sh/docs/intro/install/>
- Kubectl, <https://kubernetes.io/docs/tasks/tools/>

For developing:

- Kind, <https://kind.sigs.k8s.io/docs/user/quick-start/>
- Rust, <https://www.rust-lang.org/tools/install>
- Just, <https://github.com/casey/just>

## Install

Start be creating a default App Registration in your Azure tenant. Don't chose any Platform, just give it a name.
Add the `GroupMember.Read.All` and `User.ReadBasic.All` Application Permissions to the App Registration and create a new client secret.
If the maximun expiration date of years is not enough for you, use the `az` cli to set as many years as you want.

Create a Kubernetes secret in your cluster containing the Azure tenant, client ID and secret.

```
kubectl create secret generic az-group-manager \
--from-literal=tenant-id=<uuid> \
--from-literal=client-id=<uuid> \
--from-literal=client-secret=<secret>
```

Add the Helm repository and update.

```
helm repo add kerwood https://kerwood.github.io/helm-charts
helm repo update
```

Install the controller.

```
helm install az-group-manager kerwood/az-group-manager --namespace <namespace>
```

## How to use it

Create a `AzureGroupManager` resources with the UUID of a Azure Group in the spec.

```yaml
apiVersion: kerwood.github.com/v1
kind: AzureGroupManager
metadata:
name: my-azure-group-name-can-be-anything
spec:
groupUid: 00b9c3c9-09d1-4e58-bd89-ec3ebcfb47e6
```
The controller will create a child resource with the group information.
```yaml
apiVersion: kerwood.github.com/v1
kind: AzureGroup
metadata:
name: planet-express
...
spec:
count: 2
description: Best delivery boys in the business
displayName: Planet Express
id: 00b9c3c9-09d1-4e58-bd89-ec3ebcfb47e6
mail: [email protected]
members:
- displayName: Bender Rodriguez
id: 814a8ea1-c2d5-47ca-8f80-c838646536c3
mail: [email protected]
- displayName: Philip J. Fry
id: 631fd65d-7d72-4969-a6e5-56ad6062485f
mail: [email protected]
```
# Command Line Interface
```
Usage: az-group-manager [OPTIONS] <COMMAND>

Commands:
serve Start the service
print-crd Print the Custom Resource Definition for AzureGroup

Options:
--structured-logs Logs will be output as JSON. [env: STRUCTURED_LOGS=]
-l, --log-level <LOG_LEVEL> Log Level. [env: LOG_LEVEL=] [default: info] [possible values: trace, debug, info, warn, error]
-h, --help Print help
-V, --version Print version

Author: Patrick Kerwood <[email protected]>
```
```
Usage: az-group-manager serve [OPTIONS] --az-tenant-id <AZ_TENANT_ID> --az-client-id <AZ_CLIENT_ID> --az-client-secret <AZ_CLIENT_SECRET>

Options:
-t, --az-tenant-id <AZ_TENANT_ID>
Azure Tenant ID. [env: AZ_TENANT_ID=]
-i, --az-client-id <AZ_CLIENT_ID>
Azure App Registration Client ID. [env: AZ_CLIENT_ID=]
-s, --az-client-secret <AZ_CLIENT_SECRET>
Azure App Registration Client Secret. [env: AZ_CLIENT_SECRET=]
--structured-logs
Logs will be output as JSON. [env: STRUCTURED_LOGS=]
-b, --reconcile-time <RECONCILE_TIME>
Seconds between each reconciliation. [env: RECONCILE_TIME=] [default: 300]
-l, --log-level <LOG_LEVEL>
Log Level. [env: LOG_LEVEL=] [default: info] [possible values: trace, debug, info, warn, error]
-r, --retry-time <RETRY_TIME>
Seconds between each retry if reconciliation fails. [env: RETRY_TIME=] [default: 10]
-h, --help
Print help
```
15 changes: 15 additions & 0 deletions az_group_crd/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
[package]
name = "az_group_crd"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
kube = { version = "0.92", features = ["runtime", "derive"] }
k8s-openapi = { version = "0.22", features = ["v1_30"] }
serde = { version = "1.0.204", features = ["rc"] }
serde_derive = "1.0.204"
serde_json = "1.0.120"
serde_yaml = "0.9.34"
schemars = "0.8.21"
Loading

0 comments on commit cbab9be

Please sign in to comment.