diff --git a/.DS_Store b/.DS_Store index 618c782..024b327 100644 Binary files a/.DS_Store and b/.DS_Store differ diff --git a/.gitignore b/.gitignore index 7ff2ae4..235823f 100644 --- a/.gitignore +++ b/.gitignore @@ -3,4 +3,5 @@ data .env .env.local private_key.pem -.errorviz-version \ No newline at end of file +.errorviz-version +skaffold.generated.yaml \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json index b766505..f91f655 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -8,6 +8,7 @@ "chrono", "deks", "dotenv", + "flexauth", "inhouse", "jsonwebtoken", "lettre", diff --git a/Dockerfile b/Dockerfile index d5aa3c9..dd44cb5 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,11 +1,5 @@ # syntax=docker/dockerfile:1 -# Comments are provided throughout this file to help you get started. -# If you need more help, visit the Dockerfile reference guide at -# https://docs.docker.com/go/dockerfile-reference/ - -# Want to help us make this template better? Share your feedback here: https://forms.gle/ybq9Krt8jtBL3iCk7 - ARG RUST_VERSION=1.77 ARG APP_NAME=inhouse-auth @@ -16,19 +10,21 @@ FROM rust:${RUST_VERSION}-alpine AS dev # Set the working directory WORKDIR /app -# Install system dependencies -RUN apk add --no-cache musl-dev - -# Install OpenSSL development libraries -RUN apk add --no-cache pkgconfig openssl-dev - -# -lssl -lcrypto are required for the openssl crate -RUN apk add --no-cache openssl-libs-static +# Install system dependencies and required libraries for the build +RUN apk add --no-cache musl-dev pkgconfig openssl-dev openssl-libs-static # Install cargo-watch for auto-reloading RUN cargo install cargo-watch -# Copy the source code into the container +# Copy the Cargo.toml and Cargo.lock files separately to cache dependencies +COPY Cargo.toml Cargo.lock ./ + +# Create a dummy source file and build dependencies to cache them +RUN mkdir src && echo "fn main() {}" > src/main.rs +RUN cargo build --release || true +RUN rm -rf src + +# Copy the actual source code COPY . . # Mount the source code into the container @@ -95,29 +91,3 @@ EXPOSE ${PORT} # What the container should run when it is started. CMD ["/bin/server"] - - -################################################################################ -# Docker File for SMTP Server - -FROM ubuntu:latest AS smtp - -ARG EMAIL -ARG EMAIL_PASSWORD -ARG MAIL_NAME -ARG SMTP_DOMAIN -ARG SMTP_PORT - -RUN apt-get update && \ - apt-get install -y mailutils && \ - apt install -y postfix - -COPY /main.cf /etc/postfix/main.cf - -RUN sh -c 'echo "root: ${EMAIL}" >> /etc/aliases' && \ - sh -c 'echo "${MAIL_NAME}" >> /etc/mailname' && \ - sh -c 'echo "[${SMTP_DOMAIN}]:${SMTP_PORT} ${EMAIL}:${EMAIL_PASSWORD}" >> /etc/postfix/sasl_passwd' && \ - postmap /etc/postfix/sasl_passwd && \ - chmod 0600 /etc/postfix/sasl_passwd /etc/postfix/sasl_passwd.db - -CMD service postfix restart && tail -f /dev/null \ No newline at end of file diff --git a/Dockerfile.smtp b/Dockerfile.smtp new file mode 100644 index 0000000..8480c63 --- /dev/null +++ b/Dockerfile.smtp @@ -0,0 +1,22 @@ +# Docker File for SMTP Server +FROM ubuntu:latest AS smtp + +ARG EMAIL +ARG EMAIL_PASSWORD +ARG MAIL_NAME +ARG SMTP_DOMAIN +ARG SMTP_PORT + +RUN apt-get update && \ + apt-get install -y mailutils && \ + apt install -y postfix + +COPY /main.cf /etc/postfix/main.cf + +RUN sh -c 'echo "root: ${EMAIL}" >> /etc/aliases' && \ + sh -c 'echo "${MAIL_NAME}" >> /etc/mailname' && \ + sh -c 'echo "[${SMTP_DOMAIN}]:${SMTP_PORT} ${EMAIL}:${EMAIL_PASSWORD}" >> /etc/postfix/sasl_passwd' && \ + postmap /etc/postfix/sasl_passwd && \ + chmod 0600 /etc/postfix/sasl_passwd /etc/postfix/sasl_passwd.db + +CMD service postfix restart && tail -f /dev/null \ No newline at end of file diff --git a/compose.yaml b/compose.yaml index 7de965c..e912996 100644 --- a/compose.yaml +++ b/compose.yaml @@ -11,7 +11,7 @@ services: - mongodb - smtp-server environment: - MONGO_URI: mongodb://admin:admin@mongodb:27017 + MONGO_URI: mongodb SERVER_KEK: ${SERVER_KEK} EMAIL: ${EMAIL} EMAIL_PASSWORD: ${EMAIL_PASSWORD} @@ -19,6 +19,8 @@ services: SMTP_DOMAIN: ${SMTP_DOMAIN} SMTP_PORT: ${SMTP_PORT} X_API_KEY: ${X_API_KEY} + MONGO_INITDB_ROOT_USERNAME: ${MONGO_INITDB_ROOT_USERNAME} + MONGO_INITDB_ROOT_PASSWORD: ${MONGO_INITDB_ROOT_PASSWORD} volumes: - ./src:/app/src diff --git a/k8s/flexauth-config-map.yaml b/k8s/flexauth-config-map.yaml new file mode 100644 index 0000000..ba979f8 --- /dev/null +++ b/k8s/flexauth-config-map.yaml @@ -0,0 +1,7 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: flexauth-config + namespace: flexauth +data: + database_url: mongodb-service \ No newline at end of file diff --git a/k8s/flexauth-service-depl.yaml b/k8s/flexauth-service-depl.yaml new file mode 100644 index 0000000..5c8911d --- /dev/null +++ b/k8s/flexauth-service-depl.yaml @@ -0,0 +1,95 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: flexauth-server + namespace: flexauth + labels: + app: flexauth-server +spec: + replicas: 1 + selector: + matchLabels: + app: flexauth-server + template: + metadata: + labels: + app: flexauth-server + spec: + containers: + - name: flexauth-server + image: flexauth-server:latest + imagePullPolicy: IfNotPresent + ports: + - containerPort: 8080 + env: + - name: MONGO_URI + valueFrom: + configMapKeyRef: + name: flexauth-config + key: database_url + - name: PORT + valueFrom: + secretKeyRef: + name: flexauth-secrets + key: PORT + - name: SERVER_KEK + valueFrom: + secretKeyRef: + name: flexauth-secrets + key: SERVER_KEK + - name: EMAIL + valueFrom: + secretKeyRef: + name: flexauth-secrets + key: EMAIL + - name: EMAIL_PASSWORD + valueFrom: + secretKeyRef: + name: flexauth-secrets + key: EMAIL_PASSWORD + - name: MAIL_NAME + valueFrom: + secretKeyRef: + name: flexauth-secrets + key: MAIL_NAME + - name: SMTP_DOMAIN + valueFrom: + secretKeyRef: + name: flexauth-secrets + key: SMTP_DOMAIN + - name: SMTP_PORT + valueFrom: + secretKeyRef: + name: flexauth-secrets + key: SMTP_PORT + - name: X_API_KEY + valueFrom: + secretKeyRef: + name: flexauth-secrets + key: X_API_KEY + - name: MONGO_INITDB_ROOT_PASSWORD + valueFrom: + secretKeyRef: + name: flexauth-secrets + key: MONGO_INITDB_ROOT_PASSWORD + - name: MONGO_INITDB_ROOT_USERNAME + valueFrom: + secretKeyRef: + name: flexauth-secrets + key: MONGO_INITDB_ROOT_USERNAME + +--- +apiVersion: v1 +kind: Service +metadata: + name: flexauth-service + namespace: flexauth +spec: + type: NodePort + selector: + app: flexauth-server + ports: + - protocol: TCP + port: 8080 + targetPort: 8080 + nodePort: 30008 diff --git a/k8s/mongodb-depl.yaml b/k8s/mongodb-depl.yaml new file mode 100644 index 0000000..d465a8f --- /dev/null +++ b/k8s/mongodb-depl.yaml @@ -0,0 +1,46 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: mongodb + namespace: flexauth + labels: + app: mongodb +spec: + replicas: 1 + selector: + matchLabels: + app: mongodb + template: + metadata: + labels: + app: mongodb + spec: + containers: + - name: mongodb + image: mongo + ports: + - containerPort: 27017 + env: + - name: MONGO_INITDB_ROOT_USERNAME + valueFrom: + secretKeyRef: + name: flexauth-secrets + key: MONGO_INITDB_ROOT_USERNAME + - name: MONGO_INITDB_ROOT_PASSWORD + valueFrom: + secretKeyRef: + name: flexauth-secrets + key: MONGO_INITDB_ROOT_PASSWORD +--- +apiVersion: v1 +kind: Service +metadata: + name: mongodb-service + namespace: flexauth +spec: + selector: + app: mongodb + ports: + - protocol: TCP + port: 27017 + targetPort: 27017 diff --git a/k8s/mongodb-express-depl.yaml b/k8s/mongodb-express-depl.yaml new file mode 100644 index 0000000..bd896c8 --- /dev/null +++ b/k8s/mongodb-express-depl.yaml @@ -0,0 +1,63 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: mongodb-express + namespace: flexauth + labels: + app: mongodb-express +spec: + replicas: 1 + selector: + matchLabels: + app: mongodb-express + template: + metadata: + labels: + app: mongodb-express + spec: + containers: + - name: mongodb-express + image: mongo-express + ports: + - containerPort: 8081 + env: + - name: ME_CONFIG_MONGODB_SERVER + valueFrom: + configMapKeyRef: + name: flexauth-config + key: database_url + - name: ME_CONFIG_MONGODB_ADMINUSERNAME + valueFrom: + secretKeyRef: + name: flexauth-secrets + key: MONGO_INITDB_ROOT_USERNAME + - name: ME_CONFIG_MONGODB_ADMINPASSWORD + valueFrom: + secretKeyRef: + name: flexauth-secrets + key: MONGO_INITDB_ROOT_PASSWORD + - name: ME_CONFIG_BASICAUTH_USERNAME + valueFrom: + secretKeyRef: + name: flexauth-secrets + key: MONGO_INITDB_ROOT_USERNAME + - name: ME_CONFIG_BASICAUTH_PASSWORD + valueFrom: + secretKeyRef: + name: flexauth-secrets + key: MONGO_INITDB_ROOT_PASSWORD +--- +apiVersion: v1 +kind: Service +metadata: + name: mongodb-express-service + namespace: flexauth +spec: + selector: + app: mongodb-express + type: LoadBalancer + ports: + - protocol: TCP + port: 8081 + targetPort: 8081 + nodePort: 30000 \ No newline at end of file diff --git a/k8s/smtp-depl.yaml b/k8s/smtp-depl.yaml new file mode 100644 index 0000000..bb964d3 --- /dev/null +++ b/k8s/smtp-depl.yaml @@ -0,0 +1,60 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: smtp-server + namespace: flexauth + labels: + app: smtp-server +spec: + replicas: 1 + selector: + matchLabels: + app: smtp-server + template: + metadata: + labels: + app: smtp-server + spec: + containers: + - name: smtp-server + image: smtp-server:latest + imagePullPolicy: IfNotPresent + ports: + - containerPort: 8082 + env: + - name: SMTP_PORT + valueFrom: + secretKeyRef: + name: flexauth-secrets + key: SMTP_PORT + - name: SMTP_DOMAIN + valueFrom: + secretKeyRef: + name: flexauth-secrets + key: SMTP_DOMAIN + - name: EMAIL + valueFrom: + secretKeyRef: + name: flexauth-secrets + key: EMAIL + - name: EMAIL_PASSWORD + valueFrom: + secretKeyRef: + name: flexauth-secrets + key: EMAIL_PASSWORD + +--- + +apiVersion: v1 +kind: Service +metadata: + name: smtp-server-service + namespace: flexauth +spec: + selector: + app: smtp-server + type: LoadBalancer + ports: + - protocol: TCP + port: 8082 + targetPort: 8082 \ No newline at end of file diff --git a/makefile b/makefile index aee28b2..2edd37d 100644 --- a/makefile +++ b/makefile @@ -1,9 +1,12 @@ +################################################# Initial Setup ################################################# + + # Define the list of required environment variables for the root .env file REQUIRED_ENV_VARS = PORT SERVER_KEK EMAIL_PASSWORD EMAIL MAIL_NAME SMTP_DOMAIN SMTP_PORT MONGO_INITDB_ROOT_USERNAME MONGO_INITDB_ROOT_PASSWORD # Default target to check and update .env file .PHONY: setup -setup: update-root-env update-ui-env check-private-key +setup: update-root-env check-private-key # Target to check and update the root .env file .PHONY: update-root-env @@ -30,25 +33,6 @@ update-root-env: echo "✅ X_API_KEY"; \ fi -# Target to create or overwrite the .env file in ./ui folder -.PHONY: update-ui-env -update-ui-env: - @if [ ! -f .env ]; then \ - echo "Root .env file does not exist. Please run 'make check-env' first."; \ - exit 1; \ - fi; \ - PORT=$$(grep -E "^PORT=" .env | cut -d '=' -f 2); \ - X_API_KEY=$$(grep -E "^X_API_KEY=" .env | cut -d '=' -f 2); \ - if [ -z "$$PORT" ] || [ -z "$$X_API_KEY" ]; then \ - echo "Required variables PORT or X_API_KEY are missing in the root .env file."; \ - exit 1; \ - fi; \ - echo "Creating ./ui/.env file with the necessary environment variables..."; \ - echo "X_API_KEY=$$X_API_KEY" > ./ui/.env; \ - echo "NEXT_PUBLIC_API_BASE_URL=http://localhost:$$PORT" >> ./ui/.env; \ - echo "NEXT_PUBLIC_ENDPOINT=http://localhost:3000" >> ./ui/.env; \ - echo "✅ UI .env file created successfully." - # Target to check and generate private_key.pem if it doesn't exist .PHONY: check-private-key @@ -61,32 +45,93 @@ check-private-key: echo "🔑 Generated private_key.pem"; \ fi -# Target to run the server using Docker Compose with --build option -.PHONY: build-run-server -build-run-server: setup - docker compose up --build +################################################# Docker Setups ################################################# + +# Build the Docker image for the server target dev only +.PHONY: flexauth-build-docker +build-server: check-private-key + docker build -f Dockerfile . -t flexauth-server:dev --target dev # Target to run the server using Docker Compose without --build option -.PHONY: run-server -run-server: setup +.PHONY: flexauth-up-docker +flexauth-up-docker: setup docker compose up -# Target to build the ui / next app using npm i -.PHONY: build-ui -build-ui: - cd ui; \ - npm i - -# Target to run the ui / next app using npm run dev -.PHONY: run-ui -run-ui: setup - @if lsof -i:3000 -t > /dev/null ; then \ - echo "PORT:3000 is busy, so can't start the dashboard. Kill the process if there's anything running."; \ - exit 1; \ +# Target to run the server using Docker Compose with --build option +.PHONY: flexauth-build-up-docker +flexauth-build-up-docker: setup + docker compose up --build + +################################################# Kubernetes Setups ################################################# + +# Define the .env file and the skaffold files +ENV_FILE := .env +SKAFFOLD_TEMPLATE := skaffold.template.yaml +SKAFFOLD_GENERATED := skaffold.generated.yaml +NAMESPACE=flexauth +SECRET=flexauth-secrets + +# Load .env file and export all variables for Makefile +include $(ENV_FILE) +export $(shell sed 's/=.*//' $(ENV_FILE)) + +# Generate the skaffold.yaml file with envsubst +$(SKAFFOLD_GENERATED): $(SKAFFOLD_TEMPLATE) + @echo "Generating $(SKAFFOLD_GENERATED) with environment variables..." + @envsubst '$$EMAIL $$EMAIL_PASSWORD $$MAIL_NAME $$SMTP_DOMAIN $$SMTP_PORT' < $(SKAFFOLD_TEMPLATE) > $(SKAFFOLD_GENERATED) + @echo "$(SKAFFOLD_GENERATED) generated successfully." + +create-namespace: + @echo "Creating namespace $(NAMESPACE)..." + @if kubectl get namespace $(NAMESPACE) >/dev/null 2>&1; then \ + echo "Namespace $(NAMESPACE) already exists."; \ else \ - cd ui; \ - if [ ! -d node_modules ]; then \ - npm i; \ - fi; \ - npm run dev; \ + kubectl create namespace $(NAMESPACE) || (echo "Failed to create namespace." && exit 1); \ + fi + +# Take envs from .env then encode them to base64 and create a secret in k8s using bash +.PHONY: create-secret +create-secret: + @echo "Creating secret in k8s..." + @if kubectl get secret $(SECRET) -n $(NAMESPACE) >/dev/null 2>&1; then \ + echo "Secret $(SECRET) already exists. Overwriting..."; \ + kubectl delete secret $(SECRET) -n $(NAMESPACE); \ + fi && \ + kubectl create secret generic $(SECRET) --from-env-file=.env -n $(NAMESPACE) || (echo "Failed to create secret." && exit 1) + +# Run Minikube +.PHONY: minikube-up +minikube-up: + @echo "Running Skaffold..." + @echo "Checking Minikube status..." + @if minikube status | grep -q "host: Running"; then \ + echo "Minikube is already running."; \ + else \ + echo "Starting Minikube..."; \ + minikube start --driver=docker || (echo "Minikube failed to start." && exit 1); \ fi + +# Clean up generated files +.PHONY: clean +clean: + @echo "Cleaning up generated files..." + @rm -f $(SKAFFOLD_GENERATED) + @echo "Clean-up complete." + +# Run flexauth using Skaffold +.PHONY: flexauth-up-k8s +up-k8s: + @skaffold run -f $(SKAFFOLD_GENERATED) + +# Delete all the resources +.PHONY: flexauth-down-k8s +down-k8s: + @echo "Deleting all resources..." + @kubectl delete -f k8s/ + @kubectl delete secret flexauth-secrets + @kubectl delete namespace $(NAMESPACE) + @echo "All resources deleted." + +# Final targets +flexauth-up-k8s:setup minikube-up create-namespace create-secret $(SKAFFOLD_GENERATED) up-k8s clean +flexauth-down-k8s: down-k8s clean diff --git a/skaffold.template.yaml b/skaffold.template.yaml new file mode 100644 index 0000000..d09834b --- /dev/null +++ b/skaffold.template.yaml @@ -0,0 +1,26 @@ +apiVersion: skaffold/v2beta11 +kind: Config + +build: + artifacts: + - image: flexauth-server + context: . + docker: + dockerfile: Dockerfile + target: dev + - image: smtp-server + context: . + docker: + dockerfile: Dockerfile.smtp + target: smtp + buildArgs: + EMAIL: "${EMAIL}" + EMAIL_PASSWORD: "${EMAIL_PASSWORD}" + MAIL_NAME: "${MAIL_NAME}" + SMTP_DOMAIN: "${SMTP_DOMAIN}" + SMTP_PORT: "${SMTP_PORT}" + +deploy: + kubectl: + manifests: + - k8s/* diff --git a/src/config/db_connection_handler.rs b/src/config/db_connection_handler.rs index 80cc0db..3fb605e 100644 --- a/src/config/db_connection_handler.rs +++ b/src/config/db_connection_handler.rs @@ -7,16 +7,25 @@ use std::error::Error; pub async fn connect() -> Result> { // Load the MongoDB connection string from an environment variable: - let client_uri = env::var("MONGO_URI").unwrap_or( - "mongodb://admin:admin@localhost:27017/?directConnection=true&retryWrites=true&w=majority" - .to_string(), + let client_uri_main = env::var("MONGO_URI").unwrap_or("localhost".to_string()); + + let client_uri = format!( + "mongodb://{}:{}@{}:27017/?directConnection=true&retryWrites=true&w=majority", + env::var("MONGO_INITDB_ROOT_USERNAME").expect("MONGO_INITDB_ROOT_USERNAME required"), + env::var("MONGO_INITDB_ROOT_PASSWORD").expect("MONGO_INITDB_ROOT_PASSWORD required"), + client_uri_main ); - // A Client is needed to connect to MongoDB: - // An extra line of code to work around a DNS issue on Windows: let options = - ClientOptions::parse_with_resolver_config(&client_uri, ResolverConfig::cloudflare()) - .await?; + match ClientOptions::parse_with_resolver_config(&client_uri, ResolverConfig::cloudflare()) + .await + { + Ok(options) => options, + Err(e) => { + eprintln!(">> Error parsing client options: {:?}", e); + std::process::exit(1); + } + }; let client = Client::with_options(options.clone())?; // Print success message if the connection is successful or an error message if it fails: