mirror of
https://github.com/freedbygrace/ActiveDirectoryManager.git
synced 2026-07-26 11:59:14 +00:00
Reorganize infrastructure as code and implement versioning schema
This commit is contained in:
@@ -1,69 +0,0 @@
|
||||
name: Docker
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ "main" ]
|
||||
tags: [ 'v*.*.*' ]
|
||||
pull_request:
|
||||
branches: [ "main" ]
|
||||
|
||||
env:
|
||||
# Use docker.io for Docker Hub if empty
|
||||
REGISTRY: docker.io
|
||||
# github.repository as <account>/<repo>
|
||||
IMAGE_NAME: ${{ github.repository }}
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
# This is needed for token authentication
|
||||
id-token: write
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
|
||||
# Workaround: https://github.com/docker/build-push-action/issues/461
|
||||
- name: Setup Docker buildx
|
||||
uses: docker/setup-buildx-action@79abd3f86f79a9d68a23c75a09a9a85889262adf
|
||||
|
||||
# Login against a Docker registry
|
||||
# https://github.com/docker/login-action
|
||||
- name: Log into registry ${{ env.REGISTRY }}
|
||||
if: github.event_name != 'pull_request'
|
||||
uses: docker/login-action@28218f9b04b4f3f62068d7b6ce6ca5b26e35336c
|
||||
with:
|
||||
registry: ${{ env.REGISTRY }}
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
|
||||
# Extract metadata (tags, labels) for Docker
|
||||
# https://github.com/docker/metadata-action
|
||||
- name: Extract Docker metadata
|
||||
id: meta
|
||||
uses: docker/metadata-action@98669ae865ea3cffbcbaa878cf57c20bbf1c6c38
|
||||
with:
|
||||
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
|
||||
tags: |
|
||||
type=ref,event=branch
|
||||
type=ref,event=pr
|
||||
type=semver,pattern={{version}}
|
||||
type=semver,pattern={{major}}.{{minor}}
|
||||
type=semver,pattern={{major}}
|
||||
type=sha
|
||||
|
||||
# Build and push Docker image with Buildx
|
||||
# https://github.com/docker/build-push-action
|
||||
- name: Build and push Docker image
|
||||
id: build-and-push
|
||||
uses: docker/build-push-action@ac9327eae2b366085ac7f6a2d02df8aa8ead720a
|
||||
with:
|
||||
context: .
|
||||
push: ${{ github.event_name != 'pull_request' }}
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
cache-from: type=gha
|
||||
cache-to: type=gha,mode=max
|
||||
+7
-3
@@ -53,7 +53,7 @@ This document provides detailed instructions for deploying the Active Directory
|
||||
```bash
|
||||
cp .env.example .env
|
||||
```
|
||||
|
||||
|
||||
Edit the .env file with your specific configuration:
|
||||
```bash
|
||||
nano .env
|
||||
@@ -62,9 +62,9 @@ This document provides detailed instructions for deploying the Active Directory
|
||||
3. **SSL Configuration**
|
||||
|
||||
For production environments, the application is designed to work behind a reverse proxy or load balancer that handles SSL termination.
|
||||
|
||||
|
||||
If you need to implement SSL directly in your environment, consider:
|
||||
|
||||
|
||||
- Using a reverse proxy like Nginx or Traefik in front of the application
|
||||
- Setting up SSL termination at the infrastructure level (e.g., using AWS Application Load Balancer)
|
||||
- Configuring your cloud provider's SSL management services
|
||||
@@ -391,6 +391,8 @@ For deployment on Microsoft Azure:
|
||||
|
||||
Detailed Azure deployment instructions can be found in [AZURE_DEPLOYMENT.md](AZURE_DEPLOYMENT.md).
|
||||
|
||||
For comprehensive Kubernetes deployment instructions for any cloud provider, refer to the [Kubernetes Deployment Guide](docs/kubernetes-deployment.md).
|
||||
|
||||
### Google Cloud Deployment
|
||||
|
||||
For deployment on Google Cloud Platform:
|
||||
@@ -411,6 +413,8 @@ For deployment on Google Cloud Platform:
|
||||
|
||||
Detailed GCP deployment instructions can be found in [GCP_DEPLOYMENT.md](GCP_DEPLOYMENT.md).
|
||||
|
||||
For comprehensive Kubernetes deployment instructions for any cloud provider, refer to the [Kubernetes Deployment Guide](docs/kubernetes-deployment.md).
|
||||
|
||||
## Production Best Practices
|
||||
|
||||
### Security Considerations
|
||||
|
||||
@@ -23,6 +23,9 @@ The Active Directory Management Platform provides the following key features:
|
||||
|
||||
### Core Functionality
|
||||
- **User Management**: Create, read, update, and delete Active Directory users with comprehensive attribute support
|
||||
- Password reset with policy validation options
|
||||
- Account enabling/disabling
|
||||
- Bulk account management operations
|
||||
- **Group Management**: Manage security and distribution groups, including nested group structures
|
||||
- **Organizational Unit (OU) Management**: Create and manage the hierarchical OU structure
|
||||
- **Computer Management**: Manage computer accounts with detailed property configuration
|
||||
@@ -76,6 +79,8 @@ The Active Directory Management Platform provides the following key features:
|
||||
|
||||
### DevOps
|
||||
- **Docker**: Containerization platform for consistent deployment
|
||||
- **Kubernetes**: Container orchestration for scalable deployments
|
||||
- **Infrastructure as Code (IaC)**: Deployment configurations for Docker and Kubernetes
|
||||
|
||||
## Architecture
|
||||
|
||||
@@ -111,8 +116,8 @@ The application follows a modern web architecture with clear separation of conce
|
||||
|
||||
3. Create a .env file from the example:
|
||||
```bash
|
||||
cp .env.example .env
|
||||
# Edit .env with your configuration
|
||||
cp iac/docker/.env.example iac/docker/.env
|
||||
# Edit iac/docker/.env with your configuration
|
||||
```
|
||||
|
||||
4. Set up the database:
|
||||
@@ -142,8 +147,8 @@ The application follows a modern web architecture with clear separation of conce
|
||||
|
||||
2. Create a .env file from the example:
|
||||
```bash
|
||||
cp .env.example .env
|
||||
# Edit .env with your production configuration
|
||||
cp iac/docker/.env.example iac/docker/.env
|
||||
# Edit iac/docker/.env with your production configuration
|
||||
```
|
||||
|
||||
3. Set up environment variables for production:
|
||||
@@ -155,6 +160,7 @@ The application follows a modern web architecture with clear separation of conce
|
||||
|
||||
4. Start the application stack:
|
||||
```bash
|
||||
cd iac/docker
|
||||
docker-compose up -d
|
||||
```
|
||||
|
||||
@@ -187,6 +193,10 @@ The application is also available as a pre-built Docker image:
|
||||
|
||||
For manual deployment instructions, refer to the [Deployment Guide](DEPLOYMENT.md).
|
||||
|
||||
#### Kubernetes Deployment
|
||||
|
||||
For Kubernetes deployment instructions, refer to the [Kubernetes Deployment Guide](docs/kubernetes-deployment.md).
|
||||
|
||||
## API Documentation
|
||||
|
||||
The API is thoroughly documented using the OpenAPI specification (Swagger):
|
||||
@@ -202,6 +212,10 @@ The API is thoroughly documented using the OpenAPI specification (Swagger):
|
||||
- **Response Format**: Consistent JSON structure with appropriate status codes
|
||||
- **Error Handling**: Descriptive error messages and appropriate HTTP status codes
|
||||
|
||||
### API Examples
|
||||
|
||||
For examples of using the API, including the password reset and account management endpoints, refer to the [API Examples Guide](docs/api-examples.md).
|
||||
|
||||
### Filterable Endpoints
|
||||
|
||||
All list endpoints support filtering with a flexible query syntax:
|
||||
|
||||
@@ -0,0 +1,319 @@
|
||||
# API Examples
|
||||
|
||||
This document provides examples of using the Active Directory Management API, including the new password reset and account management endpoints.
|
||||
|
||||
## Table of Contents
|
||||
|
||||
- [Authentication](#authentication)
|
||||
- [User Management](#user-management)
|
||||
- [Password Management](#password-management)
|
||||
- [Account Status Management](#account-status-management)
|
||||
- [Group Management](#group-management)
|
||||
- [Bulk Operations](#bulk-operations)
|
||||
- [Error Handling](#error-handling)
|
||||
|
||||
## Authentication
|
||||
|
||||
### Login
|
||||
|
||||
```bash
|
||||
curl -X POST http://localhost:5000/api/auth/login \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"username": "admin",
|
||||
"password": "your-password"
|
||||
}'
|
||||
```
|
||||
|
||||
Response:
|
||||
|
||||
```json
|
||||
{
|
||||
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
|
||||
"user": {
|
||||
"id": 1,
|
||||
"username": "admin",
|
||||
"email": "admin@example.com",
|
||||
"fullName": "System Administrator",
|
||||
"role": "admin"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Using the Token
|
||||
|
||||
For all subsequent requests, include the token in the Authorization header:
|
||||
|
||||
```bash
|
||||
curl -X GET http://localhost:5000/api/users \
|
||||
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
|
||||
```
|
||||
|
||||
## User Management
|
||||
|
||||
### Get All Users
|
||||
|
||||
```bash
|
||||
curl -X GET http://localhost:5000/api/connections/1/ad-users \
|
||||
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
|
||||
```
|
||||
|
||||
### Get User by ObjectGUID
|
||||
|
||||
```bash
|
||||
curl -X GET http://localhost:5000/api/connections/1/ad-users/a1b2c3d4-e5f6-7890-abcd-ef1234567890 \
|
||||
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
|
||||
```
|
||||
|
||||
### Create User
|
||||
|
||||
```bash
|
||||
curl -X POST http://localhost:5000/api/connections/1/ad-users \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." \
|
||||
-d '{
|
||||
"sAMAccountName": "jdoe",
|
||||
"givenName": "John",
|
||||
"sn": "Doe",
|
||||
"displayName": "John Doe",
|
||||
"mail": "jdoe@example.com",
|
||||
"userPrincipalName": "jdoe@example.com",
|
||||
"parentOU": "OU=Users,DC=example,DC=com",
|
||||
"password": "SecurePassword123!",
|
||||
"enabled": true
|
||||
}'
|
||||
```
|
||||
|
||||
### Update User
|
||||
|
||||
```bash
|
||||
curl -X PATCH http://localhost:5000/api/connections/1/ad-users/a1b2c3d4-e5f6-7890-abcd-ef1234567890 \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." \
|
||||
-d '{
|
||||
"displayName": "John A. Doe",
|
||||
"mail": "john.doe@example.com",
|
||||
"telephoneNumber": "+1 (555) 123-4567"
|
||||
}'
|
||||
```
|
||||
|
||||
### Delete User
|
||||
|
||||
```bash
|
||||
curl -X DELETE http://localhost:5000/api/connections/1/ad-users/a1b2c3d4-e5f6-7890-abcd-ef1234567890 \
|
||||
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
|
||||
```
|
||||
|
||||
## Password Management
|
||||
|
||||
### Reset User Password
|
||||
|
||||
```bash
|
||||
curl -X POST http://localhost:5000/api/connections/1/reset-password \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." \
|
||||
-d '{
|
||||
"userObjectGUID": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
|
||||
"newPassword": "NewSecurePassword456!",
|
||||
"skipValidation": false,
|
||||
"requirePasswordChangeAtNextLogon": true
|
||||
}'
|
||||
```
|
||||
|
||||
Response:
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "Password reset successful for user with GUID a1b2c3d4-e5f6-7890-abcd-ef1234567890"
|
||||
}
|
||||
```
|
||||
|
||||
### Reset Password with Skip Validation
|
||||
|
||||
For scenarios where you need to bypass password policy validation:
|
||||
|
||||
```bash
|
||||
curl -X POST http://localhost:5000/api/connections/1/reset-password \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." \
|
||||
-d '{
|
||||
"userObjectGUID": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
|
||||
"newPassword": "TempPass123",
|
||||
"skipValidation": true,
|
||||
"requirePasswordChangeAtNextLogon": true
|
||||
}'
|
||||
```
|
||||
|
||||
### Reset Password Without Requiring Change at Next Logon
|
||||
|
||||
```bash
|
||||
curl -X POST http://localhost:5000/api/connections/1/reset-password \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." \
|
||||
-d '{
|
||||
"userObjectGUID": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
|
||||
"newPassword": "NewSecurePassword456!",
|
||||
"requirePasswordChangeAtNextLogon": false
|
||||
}'
|
||||
```
|
||||
|
||||
## Account Status Management
|
||||
|
||||
### Enable User Account
|
||||
|
||||
```bash
|
||||
curl -X POST http://localhost:5000/api/connections/1/enable-user-account \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." \
|
||||
-d '{
|
||||
"userObjectGUID": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
|
||||
"enabled": true
|
||||
}'
|
||||
```
|
||||
|
||||
Response:
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "User account enabled successfully for user with GUID a1b2c3d4-e5f6-7890-abcd-ef1234567890"
|
||||
}
|
||||
```
|
||||
|
||||
### Disable User Account
|
||||
|
||||
```bash
|
||||
curl -X POST http://localhost:5000/api/connections/1/enable-user-account \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." \
|
||||
-d '{
|
||||
"userObjectGUID": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
|
||||
"enabled": false
|
||||
}'
|
||||
```
|
||||
|
||||
Response:
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "User account disabled successfully for user with GUID a1b2c3d4-e5f6-7890-abcd-ef1234567890"
|
||||
}
|
||||
```
|
||||
|
||||
### Bulk Enable User Accounts
|
||||
|
||||
```bash
|
||||
curl -X POST http://localhost:5000/api/connections/1/bulk-enable-user-accounts \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." \
|
||||
-d '{
|
||||
"userDNs": [
|
||||
"CN=John Doe,OU=Users,DC=example,DC=com",
|
||||
"CN=Jane Smith,OU=Users,DC=example,DC=com",
|
||||
"CN=Bob Johnson,OU=Users,DC=example,DC=com"
|
||||
],
|
||||
"enabled": true
|
||||
}'
|
||||
```
|
||||
|
||||
Response:
|
||||
|
||||
```json
|
||||
{
|
||||
"success": [
|
||||
"CN=John Doe,OU=Users,DC=example,DC=com",
|
||||
"CN=Jane Smith,OU=Users,DC=example,DC=com",
|
||||
"CN=Bob Johnson,OU=Users,DC=example,DC=com"
|
||||
],
|
||||
"failed": []
|
||||
}
|
||||
```
|
||||
|
||||
### Bulk Disable User Accounts
|
||||
|
||||
```bash
|
||||
curl -X POST http://localhost:5000/api/connections/1/bulk-enable-user-accounts \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." \
|
||||
-d '{
|
||||
"userDNs": [
|
||||
"CN=John Doe,OU=Users,DC=example,DC=com",
|
||||
"CN=Jane Smith,OU=Users,DC=example,DC=com",
|
||||
"CN=Bob Johnson,OU=Users,DC=example,DC=com"
|
||||
],
|
||||
"enabled": false
|
||||
}'
|
||||
```
|
||||
|
||||
## Group Management
|
||||
|
||||
### Add User to Group
|
||||
|
||||
```bash
|
||||
curl -X POST http://localhost:5000/api/connections/1/add-to-group \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." \
|
||||
-d '{
|
||||
"objectGUID": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
|
||||
"groupObjectGUID": "g1h2i3j4-k5l6-7890-mnop-qr1234567890",
|
||||
"objectType": "user"
|
||||
}'
|
||||
```
|
||||
|
||||
### Remove User from Group
|
||||
|
||||
```bash
|
||||
curl -X POST http://localhost:5000/api/connections/1/remove-from-group \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." \
|
||||
-d '{
|
||||
"objectGUID": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
|
||||
"groupObjectGUID": "g1h2i3j4-k5l6-7890-mnop-qr1234567890",
|
||||
"objectType": "user"
|
||||
}'
|
||||
```
|
||||
|
||||
## Error Handling
|
||||
|
||||
### Invalid Request
|
||||
|
||||
```json
|
||||
{
|
||||
"errors": [
|
||||
{
|
||||
"code": "invalid_type",
|
||||
"expected": "string",
|
||||
"received": "undefined",
|
||||
"path": ["userObjectGUID"],
|
||||
"message": "User ObjectGUID is required"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### User Not Found
|
||||
|
||||
```json
|
||||
{
|
||||
"message": "User not found"
|
||||
}
|
||||
```
|
||||
|
||||
### Permission Denied
|
||||
|
||||
```json
|
||||
{
|
||||
"message": "You do not have permission to perform this action"
|
||||
}
|
||||
```
|
||||
|
||||
### LDAP Operation Failed
|
||||
|
||||
```json
|
||||
{
|
||||
"message": "Failed to reset password",
|
||||
"error": "LDAP operation failed: Constraint violation"
|
||||
}
|
||||
```
|
||||
@@ -0,0 +1,316 @@
|
||||
# Deployment Guide
|
||||
|
||||
This guide provides instructions for deploying the Active Directory Management application using Docker, Docker Compose, and Kubernetes.
|
||||
|
||||
## Table of Contents
|
||||
|
||||
- [Docker Deployment](#docker-deployment)
|
||||
- [Building the Docker Image](#building-the-docker-image)
|
||||
- [Running with Docker](#running-with-docker)
|
||||
- [Environment Variables](#environment-variables)
|
||||
- [Docker Compose Deployment](#docker-compose-deployment)
|
||||
- [Configuration](#configuration)
|
||||
- [Starting the Services](#starting-the-services)
|
||||
- [Stopping the Services](#stopping-the-services)
|
||||
- [Kubernetes Deployment](#kubernetes-deployment)
|
||||
- [Prerequisites](#prerequisites)
|
||||
- [Configuration](#kubernetes-configuration)
|
||||
- [Deployment](#deployment)
|
||||
- [Accessing the Application](#accessing-the-application)
|
||||
- [Scaling](#scaling)
|
||||
- [Updating](#updating)
|
||||
- [Monitoring](#monitoring)
|
||||
- [Production Considerations](#production-considerations)
|
||||
- [Security](#security)
|
||||
- [Backups](#backups)
|
||||
- [High Availability](#high-availability)
|
||||
|
||||
## Docker Deployment
|
||||
|
||||
### Building the Docker Image
|
||||
|
||||
To build the Docker image using the provided build scripts:
|
||||
|
||||
#### Linux/macOS:
|
||||
```bash
|
||||
# Navigate to the iac/docker directory
|
||||
cd iac/docker
|
||||
|
||||
# Make the script executable
|
||||
chmod +x build.sh
|
||||
|
||||
# Build the image with default settings
|
||||
./build.sh
|
||||
|
||||
# Build with custom tag
|
||||
./build.sh --tag v1.0.0
|
||||
|
||||
# Build and push to a registry
|
||||
./build.sh --registry your-registry.com --tag v1.0.0 --push
|
||||
```
|
||||
|
||||
#### Windows:
|
||||
```powershell
|
||||
# Navigate to the iac/docker directory
|
||||
cd iac\docker
|
||||
|
||||
# Build the image with default settings
|
||||
.\build.ps1
|
||||
|
||||
# Build with custom tag
|
||||
.\build.ps1 -tag v1.0.0
|
||||
|
||||
# Build and push to a registry
|
||||
.\build.ps1 -registry your-registry.com -tag v1.0.0 -push
|
||||
```
|
||||
|
||||
#### Manually:
|
||||
```bash
|
||||
# Navigate to the project root
|
||||
cd /path/to/project
|
||||
|
||||
# Build the image
|
||||
docker build -t ad-management:latest -f iac/docker/Dockerfile .
|
||||
```
|
||||
|
||||
### Running with Docker
|
||||
|
||||
To run the application with Docker:
|
||||
|
||||
```bash
|
||||
docker run -d --name ad-management \
|
||||
-p 5000:5000 \
|
||||
-e NODE_ENV=production \
|
||||
-e POSTGRES_HOST=your-postgres-host \
|
||||
-e POSTGRES_PORT=5432 \
|
||||
-e POSTGRES_DB=admgr \
|
||||
-e POSTGRES_USER=postgres \
|
||||
-e POSTGRES_PASSWORD=your-password \
|
||||
-e REDIS_HOST=your-redis-host \
|
||||
-e REDIS_PORT=6379 \
|
||||
-e JWT_SECRET=your-jwt-secret \
|
||||
-e SESSION_SECRET=your-session-secret \
|
||||
ad-management:latest
|
||||
```
|
||||
|
||||
### Environment Variables
|
||||
|
||||
The application uses the following environment variables:
|
||||
|
||||
| Variable | Description | Default |
|
||||
|----------|-------------|---------|
|
||||
| `NODE_ENV` | Environment mode | `development` |
|
||||
| `PORT` | Port to run the server on | `5000` |
|
||||
| `BASE_URL` | Base URL for the application | `http://localhost:5000` |
|
||||
| `POSTGRES_HOST` | PostgreSQL host | `localhost` |
|
||||
| `POSTGRES_PORT` | PostgreSQL port | `5432` |
|
||||
| `POSTGRES_DB` | PostgreSQL database name | `admgr` |
|
||||
| `POSTGRES_USER` | PostgreSQL username | `postgres` |
|
||||
| `POSTGRES_PASSWORD` | PostgreSQL password | - |
|
||||
| `REDIS_HOST` | Redis host | `localhost` |
|
||||
| `REDIS_PORT` | Redis port | `6379` |
|
||||
| `JWT_SECRET` | Secret for JWT tokens | - |
|
||||
| `SESSION_SECRET` | Secret for session cookies | - |
|
||||
| `DEFAULT_ADMIN_USERNAME` | Default admin username | `admin` |
|
||||
| `DEFAULT_ADMIN_PASSWORD` | Default admin password | - |
|
||||
| `DEFAULT_ADMIN_EMAIL` | Default admin email | - |
|
||||
| `DEFAULT_ADMIN_FULLNAME` | Default admin full name | `System Administrator` |
|
||||
| `DISABLE_REGISTRATION` | Disable user registration | `false` |
|
||||
|
||||
## Docker Compose Deployment
|
||||
|
||||
### Configuration
|
||||
|
||||
The application includes a `docker-compose.yml` file for easy deployment. You can customize the environment variables by creating or modifying the `.env` file in the `iac/docker` directory.
|
||||
|
||||
Example `.env` file:
|
||||
|
||||
```
|
||||
NODE_ENV=production
|
||||
PORT=5000
|
||||
BASE_URL=http://localhost:5000
|
||||
POSTGRES_HOST=postgres
|
||||
POSTGRES_PORT=5432
|
||||
POSTGRES_DB=admgr
|
||||
POSTGRES_USER=postgres
|
||||
POSTGRES_PASSWORD=your-postgres-password
|
||||
REDIS_HOST=redis
|
||||
REDIS_PORT=6379
|
||||
JWT_SECRET=your-jwt-secret
|
||||
SESSION_SECRET=your-session-secret
|
||||
DEFAULT_ADMIN_USERNAME=admin
|
||||
DEFAULT_ADMIN_PASSWORD=your-admin-password
|
||||
DEFAULT_ADMIN_EMAIL=admin@example.com
|
||||
DEFAULT_ADMIN_FULLNAME=System Administrator
|
||||
DISABLE_REGISTRATION=false
|
||||
```
|
||||
|
||||
### Starting the Services
|
||||
|
||||
To start all services:
|
||||
|
||||
```bash
|
||||
# Navigate to the iac/docker directory
|
||||
cd iac/docker
|
||||
|
||||
# Start the application stack
|
||||
docker-compose up -d
|
||||
```
|
||||
|
||||
This will start the application, PostgreSQL, and Redis containers.
|
||||
|
||||
### Stopping the Services
|
||||
|
||||
To stop all services:
|
||||
|
||||
```bash
|
||||
# Navigate to the iac/docker directory
|
||||
cd iac/docker
|
||||
|
||||
# Stop the application stack
|
||||
docker-compose down
|
||||
```
|
||||
|
||||
To stop and remove all data volumes:
|
||||
|
||||
```bash
|
||||
# Navigate to the iac/docker directory
|
||||
cd iac/docker
|
||||
|
||||
# Stop the application stack and remove volumes
|
||||
docker-compose down -v
|
||||
```
|
||||
|
||||
## Kubernetes Deployment
|
||||
|
||||
### Prerequisites
|
||||
|
||||
- Kubernetes cluster (v1.19+)
|
||||
- kubectl configured to communicate with your cluster
|
||||
- [Kustomize](https://kustomize.io/) (v4.0+) or kubectl v1.14+ which includes kustomize
|
||||
- Optional: Ingress controller (e.g., NGINX Ingress Controller)
|
||||
- Optional: cert-manager for TLS certificates
|
||||
|
||||
### Kubernetes Configuration
|
||||
|
||||
The Kubernetes manifests are located in the `iac/kubernetes/` directory. Before deploying, you should customize the following files:
|
||||
|
||||
1. `iac/kubernetes/configmap.yaml`: Update environment variables
|
||||
2. `iac/kubernetes/secrets.yaml`: Update secrets (use base64-encoded values)
|
||||
3. `iac/kubernetes/deployment.yaml`: Update resource limits if needed
|
||||
4. `iac/kubernetes/ingress.yaml`: Update host name and TLS configuration
|
||||
|
||||
### Deployment
|
||||
|
||||
To deploy the application to Kubernetes:
|
||||
|
||||
```bash
|
||||
# Navigate to the iac/kubernetes directory
|
||||
cd iac/kubernetes
|
||||
|
||||
# Apply all resources
|
||||
kubectl apply -k .
|
||||
|
||||
# Or from anywhere in the project
|
||||
kubectl apply -k iac/kubernetes
|
||||
```
|
||||
|
||||
This will create:
|
||||
- A namespace called `ad-management`
|
||||
- ConfigMap and Secret for environment variables
|
||||
- PostgreSQL StatefulSet with persistent storage
|
||||
- Redis StatefulSet with persistent storage
|
||||
- Application Deployment with 2 replicas
|
||||
- Services for all components
|
||||
- Ingress for external access
|
||||
|
||||
### Accessing the Application
|
||||
|
||||
If you've configured the Ingress, the application will be available at the hostname specified in `kubernetes/ingress.yaml`.
|
||||
|
||||
Without Ingress, you can use port-forwarding to access the application:
|
||||
|
||||
```bash
|
||||
kubectl port-forward -n ad-management svc/ad-management 5000:80
|
||||
```
|
||||
|
||||
Then access the application at http://localhost:5000.
|
||||
|
||||
### Scaling
|
||||
|
||||
To scale the application:
|
||||
|
||||
```bash
|
||||
kubectl scale -n ad-management deployment/ad-management --replicas=3
|
||||
```
|
||||
|
||||
### Updating
|
||||
|
||||
To update the application to a new version:
|
||||
|
||||
1. Build and push the new Docker image
|
||||
2. Update the image tag in `kubernetes/deployment.yaml`
|
||||
3. Apply the changes:
|
||||
|
||||
```bash
|
||||
kubectl apply -k kubernetes/
|
||||
```
|
||||
|
||||
Or use kubectl set image:
|
||||
|
||||
```bash
|
||||
kubectl set image -n ad-management deployment/ad-management ad-management=ad-management:new-tag
|
||||
```
|
||||
|
||||
### Monitoring
|
||||
|
||||
You can monitor the application using:
|
||||
|
||||
```bash
|
||||
# Check pod status
|
||||
kubectl get pods -n ad-management
|
||||
|
||||
# View logs
|
||||
kubectl logs -n ad-management deployment/ad-management
|
||||
|
||||
# Describe deployment
|
||||
kubectl describe deployment -n ad-management ad-management
|
||||
```
|
||||
|
||||
## Production Considerations
|
||||
|
||||
### Security
|
||||
|
||||
For production deployments:
|
||||
|
||||
1. Use strong, unique passwords for all secrets
|
||||
2. Enable TLS for all connections
|
||||
3. Use network policies to restrict traffic between components
|
||||
4. Set up proper RBAC for Kubernetes resources
|
||||
5. Regularly update all components and dependencies
|
||||
6. Consider using a secrets management solution like HashiCorp Vault
|
||||
|
||||
### Backups
|
||||
|
||||
Set up regular backups for:
|
||||
|
||||
1. PostgreSQL database
|
||||
2. Redis data (if persistence is enabled)
|
||||
3. Application configuration
|
||||
|
||||
Example PostgreSQL backup:
|
||||
|
||||
```bash
|
||||
kubectl exec -n ad-management postgres-0 -- pg_dump -U postgres admgr > backup.sql
|
||||
```
|
||||
|
||||
### High Availability
|
||||
|
||||
For high availability:
|
||||
|
||||
1. Run multiple replicas of the application
|
||||
2. Use a PostgreSQL cluster with replication
|
||||
3. Configure Redis with replication or cluster mode
|
||||
4. Deploy across multiple availability zones
|
||||
5. Use a load balancer or ingress controller with multiple backends
|
||||
6. Implement proper health checks and readiness probes
|
||||
@@ -0,0 +1,324 @@
|
||||
# Kubernetes Deployment Guide
|
||||
|
||||
This guide provides detailed instructions for deploying the Active Directory Management application on Kubernetes.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Kubernetes cluster (v1.19+)
|
||||
- kubectl configured to communicate with your cluster
|
||||
- [Kustomize](https://kustomize.io/) (v4.0+) or kubectl v1.14+ which includes kustomize
|
||||
- Optional: Ingress controller (e.g., NGINX Ingress Controller)
|
||||
- Optional: cert-manager for TLS certificates
|
||||
|
||||
## Deployment Architecture
|
||||
|
||||
The Kubernetes deployment consists of:
|
||||
|
||||
- **Application Deployment**: The main application with multiple replicas
|
||||
- **PostgreSQL StatefulSet**: Database with persistent storage
|
||||
- **Redis StatefulSet**: Cache and session storage with persistent storage
|
||||
- **Services**: For internal communication between components
|
||||
- **Ingress**: For external access to the application
|
||||
- **ConfigMap and Secrets**: For configuration and sensitive data
|
||||
|
||||
All Kubernetes manifests are located in the `iac/kubernetes/` directory.
|
||||
|
||||
## Step-by-Step Deployment
|
||||
|
||||
### 1. Customize Configuration
|
||||
|
||||
Before deploying, customize the configuration files in the `iac/kubernetes/` directory:
|
||||
|
||||
#### ConfigMap (`iac/kubernetes/configmap.yaml`)
|
||||
|
||||
Update environment variables according to your environment:
|
||||
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: ad-management-config
|
||||
namespace: ad-management
|
||||
data:
|
||||
NODE_ENV: "production"
|
||||
PORT: "5000"
|
||||
BASE_URL: "https://your-domain.com" # Update this
|
||||
DEFAULT_ADMIN_USERNAME: "admin"
|
||||
DEFAULT_ADMIN_FULLNAME: "System Administrator"
|
||||
DISABLE_REGISTRATION: "false"
|
||||
POSTGRES_DB: "admgr"
|
||||
POSTGRES_USER: "postgres"
|
||||
```
|
||||
|
||||
#### Secrets (`kubernetes/secrets.yaml`)
|
||||
|
||||
Update the secrets with your own base64-encoded values:
|
||||
|
||||
```bash
|
||||
# Generate base64-encoded secrets
|
||||
echo -n "your-jwt-secret" | base64
|
||||
echo -n "your-session-secret" | base64
|
||||
echo -n "your-admin-password" | base64
|
||||
echo -n "admin@your-domain.com" | base64
|
||||
echo -n "your-postgres-password" | base64
|
||||
```
|
||||
|
||||
Then update `iac/kubernetes/secrets.yaml`:
|
||||
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: ad-management-secrets
|
||||
namespace: ad-management
|
||||
type: Opaque
|
||||
data:
|
||||
JWT_SECRET: "base64-encoded-jwt-secret"
|
||||
SESSION_SECRET: "base64-encoded-session-secret"
|
||||
DEFAULT_ADMIN_PASSWORD: "base64-encoded-admin-password"
|
||||
DEFAULT_ADMIN_EMAIL: "base64-encoded-admin-email"
|
||||
POSTGRES_PASSWORD: "base64-encoded-postgres-password"
|
||||
```
|
||||
|
||||
#### Ingress (`iac/kubernetes/ingress.yaml`)
|
||||
|
||||
Update the hostname and TLS configuration:
|
||||
|
||||
```yaml
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: ad-management-ingress
|
||||
namespace: ad-management
|
||||
annotations:
|
||||
kubernetes.io/ingress.class: "nginx"
|
||||
cert-manager.io/cluster-issuer: "letsencrypt-prod"
|
||||
nginx.ingress.kubernetes.io/ssl-redirect: "true"
|
||||
spec:
|
||||
tls:
|
||||
- hosts:
|
||||
- your-domain.com # Update this
|
||||
secretName: ad-management-tls
|
||||
rules:
|
||||
- host: your-domain.com # Update this
|
||||
http:
|
||||
paths:
|
||||
- path: /
|
||||
pathType: Prefix
|
||||
backend:
|
||||
service:
|
||||
name: ad-management
|
||||
port:
|
||||
name: http
|
||||
```
|
||||
|
||||
### 2. Deploy the Application
|
||||
|
||||
Deploy all resources using Kustomize:
|
||||
|
||||
```bash
|
||||
# Navigate to the iac/kubernetes directory
|
||||
cd iac/kubernetes
|
||||
|
||||
# Apply all resources
|
||||
kubectl apply -k .
|
||||
|
||||
# Or from anywhere in the project
|
||||
kubectl apply -k iac/kubernetes
|
||||
```
|
||||
|
||||
### 3. Verify Deployment
|
||||
|
||||
Check that all resources are created and running:
|
||||
|
||||
```bash
|
||||
# Check namespace
|
||||
kubectl get namespace ad-management
|
||||
|
||||
# Check pods
|
||||
kubectl get pods -n ad-management
|
||||
|
||||
# Check services
|
||||
kubectl get services -n ad-management
|
||||
|
||||
# Check deployments and statefulsets
|
||||
kubectl get deployment,statefulset -n ad-management
|
||||
|
||||
# Check ingress
|
||||
kubectl get ingress -n ad-management
|
||||
```
|
||||
|
||||
### 4. Access the Application
|
||||
|
||||
If you've configured the Ingress, the application will be available at your specified domain.
|
||||
|
||||
Without Ingress, use port-forwarding:
|
||||
|
||||
```bash
|
||||
kubectl port-forward -n ad-management svc/ad-management 5000:80
|
||||
```
|
||||
|
||||
Then access the application at http://localhost:5000.
|
||||
|
||||
## Common Operations
|
||||
|
||||
### Scaling the Application
|
||||
|
||||
To scale the application horizontally:
|
||||
|
||||
```bash
|
||||
kubectl scale -n ad-management deployment/ad-management --replicas=3
|
||||
```
|
||||
|
||||
### Updating the Application
|
||||
|
||||
To update the application to a new version:
|
||||
|
||||
```bash
|
||||
# Update the image
|
||||
kubectl set image -n ad-management deployment/ad-management ad-management=ad-management:new-tag
|
||||
|
||||
# Check rollout status
|
||||
kubectl rollout status -n ad-management deployment/ad-management
|
||||
```
|
||||
|
||||
### Viewing Logs
|
||||
|
||||
To view application logs:
|
||||
|
||||
```bash
|
||||
# View logs from all pods
|
||||
kubectl logs -n ad-management -l app=ad-management
|
||||
|
||||
# View logs from a specific pod
|
||||
kubectl logs -n ad-management pod/ad-management-xxxx-yyyy
|
||||
```
|
||||
|
||||
### Restarting Components
|
||||
|
||||
To restart the application:
|
||||
|
||||
```bash
|
||||
kubectl rollout restart -n ad-management deployment/ad-management
|
||||
```
|
||||
|
||||
To restart PostgreSQL or Redis:
|
||||
|
||||
```bash
|
||||
kubectl rollout restart -n ad-management statefulset/postgres
|
||||
kubectl rollout restart -n ad-management statefulset/redis
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Pod Startup Issues
|
||||
|
||||
If pods are not starting:
|
||||
|
||||
```bash
|
||||
# Check pod status
|
||||
kubectl get pods -n ad-management
|
||||
|
||||
# Describe the pod for more details
|
||||
kubectl describe pod -n ad-management pod/ad-management-xxxx-yyyy
|
||||
|
||||
# Check container logs
|
||||
kubectl logs -n ad-management pod/ad-management-xxxx-yyyy
|
||||
```
|
||||
|
||||
### Database Connection Issues
|
||||
|
||||
If the application can't connect to the database:
|
||||
|
||||
1. Check if the PostgreSQL pod is running:
|
||||
```bash
|
||||
kubectl get pods -n ad-management -l app=postgres
|
||||
```
|
||||
|
||||
2. Check PostgreSQL logs:
|
||||
```bash
|
||||
kubectl logs -n ad-management pod/postgres-0
|
||||
```
|
||||
|
||||
3. Verify the connection from the application pod:
|
||||
```bash
|
||||
kubectl exec -it -n ad-management pod/ad-management-xxxx-yyyy -- nc -zv postgres 5432
|
||||
```
|
||||
|
||||
### Ingress Issues
|
||||
|
||||
If the Ingress is not working:
|
||||
|
||||
1. Check the Ingress status:
|
||||
```bash
|
||||
kubectl describe ingress -n ad-management ad-management-ingress
|
||||
```
|
||||
|
||||
2. Check the Ingress controller logs:
|
||||
```bash
|
||||
kubectl logs -n ingress-nginx deployment/ingress-nginx-controller
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
### Example: Setting Up TLS with cert-manager
|
||||
|
||||
1. Install cert-manager:
|
||||
```bash
|
||||
kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.9.1/cert-manager.yaml
|
||||
```
|
||||
|
||||
2. Create a ClusterIssuer for Let's Encrypt:
|
||||
```yaml
|
||||
apiVersion: cert-manager.io/v1
|
||||
kind: ClusterIssuer
|
||||
metadata:
|
||||
name: letsencrypt-prod
|
||||
spec:
|
||||
acme:
|
||||
server: https://acme-v02.api.letsencrypt.org/directory
|
||||
email: your-email@example.com
|
||||
privateKeySecretRef:
|
||||
name: letsencrypt-prod
|
||||
solvers:
|
||||
- http01:
|
||||
ingress:
|
||||
class: nginx
|
||||
```
|
||||
|
||||
3. Apply the ClusterIssuer:
|
||||
```bash
|
||||
kubectl apply -f cluster-issuer.yaml
|
||||
```
|
||||
|
||||
### Example: Setting Up Monitoring with Prometheus and Grafana
|
||||
|
||||
1. Install Prometheus Operator:
|
||||
```bash
|
||||
kubectl apply -f https://github.com/prometheus-operator/kube-prometheus/releases/download/v0.10.0/manifests-0.10.0.tar.gz
|
||||
```
|
||||
|
||||
2. Create a ServiceMonitor for the application:
|
||||
```yaml
|
||||
apiVersion: monitoring.coreos.com/v1
|
||||
kind: ServiceMonitor
|
||||
metadata:
|
||||
name: ad-management
|
||||
namespace: monitoring
|
||||
spec:
|
||||
selector:
|
||||
matchLabels:
|
||||
app: ad-management
|
||||
namespaceSelector:
|
||||
matchNames:
|
||||
- ad-management
|
||||
endpoints:
|
||||
- port: http
|
||||
path: /metrics
|
||||
interval: 15s
|
||||
```
|
||||
|
||||
3. Apply the ServiceMonitor:
|
||||
```bash
|
||||
kubectl apply -f service-monitor.yaml
|
||||
```
|
||||
+257
@@ -0,0 +1,257 @@
|
||||
# Infrastructure as Code (IaC)
|
||||
|
||||
This directory contains all the infrastructure as code configurations for deploying the Active Directory Management application.
|
||||
|
||||
## Directory Structure
|
||||
|
||||
- **docker/**: Docker-related files
|
||||
- `Dockerfile`: Multi-stage Docker build file
|
||||
- `docker-compose.yml`: Docker Compose configuration
|
||||
- `build.sh`: Bash script for building and pushing Docker images (Linux/macOS)
|
||||
- `build.ps1`: PowerShell script for building and pushing Docker images (Windows)
|
||||
- `.env`: Environment variables for Docker deployment
|
||||
- `.env.example`: Example environment variables
|
||||
- `.env.production`: Production environment variables
|
||||
|
||||
- **version.txt**: Central version file in yyyy.MM.dd.HHmm format
|
||||
- **update-version.sh**: Bash script to update version.txt (Linux/macOS)
|
||||
- **update-version.ps1**: PowerShell script to update version.txt (Windows)
|
||||
- **update-all.sh**: Comprehensive script to update all version references (Linux/macOS)
|
||||
- **update-all.ps1**: Comprehensive script to update all version references (Windows)
|
||||
|
||||
- **kubernetes/**: Kubernetes manifests
|
||||
- `namespace.yaml`: Namespace definition
|
||||
- `configmap.yaml`: ConfigMap for non-sensitive configuration
|
||||
- `secrets.yaml`: Secrets for sensitive configuration
|
||||
- `postgres.yaml`: PostgreSQL StatefulSet and Service
|
||||
- `redis.yaml`: Redis StatefulSet and Service
|
||||
- `deployment.yaml`: Application Deployment and Service
|
||||
- `ingress.yaml`: Ingress for external access
|
||||
- `kustomization.yaml`: Kustomize configuration
|
||||
|
||||
## Docker
|
||||
|
||||
### Versioning
|
||||
|
||||
The application uses a versioning scheme in the format `yyyy.MM.dd.HHmm` (year, month, day, hour, minute).
|
||||
|
||||
#### Comprehensive Version Update
|
||||
|
||||
To update the version and apply it to all components (recommended):
|
||||
|
||||
On Linux/macOS:
|
||||
```bash
|
||||
# Navigate to the iac directory
|
||||
cd iac
|
||||
|
||||
# Make the script executable
|
||||
chmod +x update-all.sh
|
||||
|
||||
# Update all version references
|
||||
./update-all.sh
|
||||
```
|
||||
|
||||
On Windows:
|
||||
```powershell
|
||||
# Navigate to the iac directory
|
||||
cd iac
|
||||
|
||||
# Update all version references
|
||||
.\update-all.ps1
|
||||
```
|
||||
|
||||
#### Manual Version Update
|
||||
|
||||
To update only the version.txt file:
|
||||
|
||||
On Linux/macOS:
|
||||
```bash
|
||||
# Navigate to the iac directory
|
||||
cd iac
|
||||
|
||||
# Make the script executable
|
||||
chmod +x update-version.sh
|
||||
|
||||
# Update the version
|
||||
./update-version.sh
|
||||
```
|
||||
|
||||
On Windows:
|
||||
```powershell
|
||||
# Navigate to the iac directory
|
||||
cd iac
|
||||
|
||||
# Update the version
|
||||
.\update-version.ps1
|
||||
```
|
||||
|
||||
### Building Docker Images
|
||||
|
||||
#### Using the build scripts
|
||||
|
||||
On Linux/macOS:
|
||||
```bash
|
||||
# Navigate to the iac/docker directory
|
||||
cd iac/docker
|
||||
|
||||
# Make the script executable
|
||||
chmod +x build.sh
|
||||
|
||||
# Build the image with version from version.txt
|
||||
./build.sh
|
||||
|
||||
# Build with custom tag
|
||||
./build.sh --tag 2025.05.21.1430
|
||||
|
||||
# Build and push to a registry
|
||||
./build.sh --registry your-registry.com --push
|
||||
```
|
||||
|
||||
On Windows:
|
||||
```powershell
|
||||
# Navigate to the iac/docker directory
|
||||
cd iac\docker
|
||||
|
||||
# Build the image with version from version.txt
|
||||
.\build.ps1
|
||||
|
||||
# Build with custom tag
|
||||
.\build.ps1 -tag 2025.05.21.1430
|
||||
|
||||
# Build and push to a registry
|
||||
.\build.ps1 -registry your-registry.com -push
|
||||
```
|
||||
|
||||
#### Manually
|
||||
|
||||
```bash
|
||||
# Navigate to the project root
|
||||
cd /path/to/project
|
||||
|
||||
# Get the version from version.txt
|
||||
VERSION=$(cat iac/version.txt)
|
||||
|
||||
# Build the image
|
||||
docker build -t ActiveDirectoryManager:$VERSION -f iac/docker/Dockerfile .
|
||||
|
||||
# Tag the image for a registry
|
||||
docker tag ActiveDirectoryManager:$VERSION your-registry.com/ActiveDirectoryManager:$VERSION
|
||||
|
||||
# Push to registry
|
||||
docker push your-registry.com/ActiveDirectoryManager:$VERSION
|
||||
```
|
||||
|
||||
### Running with Docker Compose
|
||||
|
||||
```bash
|
||||
# Navigate to the iac/docker directory
|
||||
cd iac/docker
|
||||
|
||||
# Create a .env file from the example if you haven't already
|
||||
cp .env.example .env
|
||||
# Edit the .env file with your configuration
|
||||
|
||||
# Load the version from version.txt
|
||||
source .env.version
|
||||
|
||||
# Start the application stack
|
||||
docker-compose up -d
|
||||
|
||||
# View logs
|
||||
docker-compose logs -f
|
||||
|
||||
# Stop the application stack
|
||||
docker-compose down
|
||||
```
|
||||
|
||||
## Kubernetes
|
||||
|
||||
### Prerequisites
|
||||
|
||||
- Kubernetes cluster (v1.19+)
|
||||
- kubectl configured to communicate with your cluster
|
||||
- Kustomize (v4.0+) or kubectl v1.14+ which includes kustomize
|
||||
|
||||
### Updating Deployment Version
|
||||
|
||||
Before deploying, you should update the Kubernetes deployment to use the current version:
|
||||
|
||||
On Linux/macOS:
|
||||
```bash
|
||||
# Navigate to the iac/kubernetes directory
|
||||
cd iac/kubernetes
|
||||
|
||||
# Make the script executable
|
||||
chmod +x update-deployment-version.sh
|
||||
|
||||
# Update the deployment version
|
||||
./update-deployment-version.sh
|
||||
```
|
||||
|
||||
On Windows:
|
||||
```powershell
|
||||
# Navigate to the iac/kubernetes directory
|
||||
cd iac\kubernetes
|
||||
|
||||
# Update the deployment version
|
||||
.\update-deployment-version.ps1
|
||||
```
|
||||
|
||||
### Deployment
|
||||
|
||||
```bash
|
||||
# Navigate to the iac/kubernetes directory
|
||||
cd iac/kubernetes
|
||||
|
||||
# Apply all resources
|
||||
kubectl apply -k .
|
||||
|
||||
# Or from anywhere in the project
|
||||
kubectl apply -k iac/kubernetes
|
||||
```
|
||||
|
||||
### Customization
|
||||
|
||||
To customize the deployment for different environments:
|
||||
|
||||
1. Create a new directory for your environment:
|
||||
```bash
|
||||
mkdir -p iac/kubernetes/environments/production
|
||||
```
|
||||
|
||||
2. Create a kustomization.yaml file that references the base configuration:
|
||||
```yaml
|
||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
|
||||
namespace: ad-management-production
|
||||
|
||||
resources:
|
||||
- ../../ # Reference the base configuration
|
||||
|
||||
patches:
|
||||
# Add your patches here
|
||||
```
|
||||
|
||||
3. Apply the environment-specific configuration:
|
||||
```bash
|
||||
kubectl apply -k iac/kubernetes/environments/production
|
||||
```
|
||||
|
||||
## CI/CD Integration
|
||||
|
||||
The Docker build scripts are designed to be used in CI/CD pipelines. Example integration with GitHub Actions:
|
||||
|
||||
```yaml
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Build and push Docker image
|
||||
run: |
|
||||
cd iac/docker
|
||||
chmod +x build.sh
|
||||
./build.sh --registry ghcr.io --tag ${{ github.sha }} --push
|
||||
```
|
||||
@@ -0,0 +1,21 @@
|
||||
# Environment Variables for Docker Deployment
|
||||
# Copy from .env.example and customize as needed
|
||||
|
||||
# Database Configuration
|
||||
POSTGRES_USER=admanagement
|
||||
POSTGRES_PASSWORD=change_this_to_a_secure_password
|
||||
POSTGRES_DB=admanagement
|
||||
|
||||
# Application Configuration
|
||||
NODE_ENV=production
|
||||
PORT=5000
|
||||
BASE_URL=http://localhost:5000
|
||||
SESSION_SECRET=change_this_to_a_random_string
|
||||
JWT_SECRET=change_this_to_a_different_random_string
|
||||
|
||||
# Default Admin User Configuration
|
||||
DEFAULT_ADMIN_USERNAME=admin
|
||||
DEFAULT_ADMIN_PASSWORD=change_this_to_a_secure_password
|
||||
DEFAULT_ADMIN_EMAIL=admin@example.com
|
||||
DEFAULT_ADMIN_FULLNAME=System Administrator
|
||||
DISABLE_REGISTRATION=false
|
||||
@@ -53,4 +53,4 @@ DISABLE_REGISTRATION=false
|
||||
# OIDC_USERINFO_URL=https://openidconnect.googleapis.com/v1/userinfo
|
||||
# OIDC_CLIENT_ID=your_client_id
|
||||
# OIDC_CLIENT_SECRET=your_client_secret
|
||||
# OIDC_CALLBACK_URL=http://localhost:5000/api/auth/oidc/callback
|
||||
# OIDC_CALLBACK_URL=http://localhost:5000/api/auth/oidc/callback
|
||||
@@ -22,4 +22,4 @@ SESSION_COOKIE_SECURE=true
|
||||
SESSION_COOKIE_HTTPONLY=true
|
||||
|
||||
# API Settings
|
||||
SWAGGER_ENABLED=true
|
||||
SWAGGER_ENABLED=true
|
||||
@@ -0,0 +1,3 @@
|
||||
# This file is used to set the VERSION environment variable for docker-compose
|
||||
# It reads the version from the version.txt file
|
||||
VERSION=$(cat ../version.txt)
|
||||
@@ -62,4 +62,4 @@ USER appuser
|
||||
EXPOSE 5000
|
||||
|
||||
# Start the application
|
||||
CMD ["node", "dist/server/index.js"]
|
||||
CMD ["node", "dist/server/index.js"]
|
||||
@@ -0,0 +1,74 @@
|
||||
# PowerShell script for building Docker images (Windows)
|
||||
param (
|
||||
[string]$tag = "",
|
||||
[string]$registry = "",
|
||||
[switch]$push = $false,
|
||||
[string]$imageName = "ActiveDirectoryManager"
|
||||
)
|
||||
|
||||
# If no tag is provided, use the version from version.txt
|
||||
if (-not $tag) {
|
||||
$versionFile = Join-Path (Split-Path $PSScriptRoot) "version.txt"
|
||||
if (Test-Path $versionFile) {
|
||||
$tag = Get-Content $versionFile -Raw
|
||||
$tag = $tag.Trim()
|
||||
} else {
|
||||
# If version.txt doesn't exist, use current date/time in yyyy.MM.dd.HHmm format
|
||||
$tag = Get-Date -Format "yyyy.MM.dd.HHmm"
|
||||
}
|
||||
}
|
||||
|
||||
# Set error action preference to stop on any error
|
||||
$ErrorActionPreference = "Stop"
|
||||
|
||||
# Display build information
|
||||
Write-Host "Building Docker image: $imageName" -ForegroundColor Green
|
||||
Write-Host "Tag: $tag" -ForegroundColor Green
|
||||
if ($registry) {
|
||||
Write-Host "Registry: $registry" -ForegroundColor Green
|
||||
}
|
||||
|
||||
# Determine the full image name
|
||||
$fullImageName = if ($registry) { "$registry/$imageName" } else { $imageName }
|
||||
|
||||
# Check if Docker is available
|
||||
try {
|
||||
docker --version
|
||||
}
|
||||
catch {
|
||||
Write-Host "Docker is not available. Please install Docker and try again." -ForegroundColor Red
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Build the Docker image
|
||||
try {
|
||||
Write-Host "Building image: $fullImageName`:$tag" -ForegroundColor Cyan
|
||||
|
||||
# Navigate to the root directory (two levels up from the script location)
|
||||
$rootDir = (Get-Item $PSScriptRoot).Parent.Parent.FullName
|
||||
|
||||
# Build the Docker image
|
||||
docker build -t "$fullImageName`:$tag" -f "$PSScriptRoot/Dockerfile" $rootDir
|
||||
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
throw "Docker build failed with exit code $LASTEXITCODE"
|
||||
}
|
||||
|
||||
Write-Host "Successfully built image: $fullImageName`:$tag" -ForegroundColor Green
|
||||
|
||||
# Push the image if requested
|
||||
if ($push) {
|
||||
Write-Host "Pushing image to registry: $fullImageName`:$tag" -ForegroundColor Cyan
|
||||
docker push "$fullImageName`:$tag"
|
||||
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
throw "Docker push failed with exit code $LASTEXITCODE"
|
||||
}
|
||||
|
||||
Write-Host "Successfully pushed image: $fullImageName`:$tag" -ForegroundColor Green
|
||||
}
|
||||
}
|
||||
catch {
|
||||
Write-Host "Error: $_" -ForegroundColor Red
|
||||
exit 1
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
#!/bin/bash
|
||||
# Bash script for building Docker images (Linux/macOS)
|
||||
|
||||
# Default values
|
||||
TAG=""
|
||||
REGISTRY=""
|
||||
PUSH=false
|
||||
IMAGE_NAME="ActiveDirectoryManager"
|
||||
|
||||
# If no tag is provided, use the version from version.txt
|
||||
if [ -z "$TAG" ]; then
|
||||
VERSION_FILE="$(dirname "$(dirname "$0")")/version.txt"
|
||||
if [ -f "$VERSION_FILE" ]; then
|
||||
TAG=$(cat "$VERSION_FILE" | tr -d '[:space:]')
|
||||
else
|
||||
# If version.txt doesn't exist, use current date/time in yyyy.MM.dd.HHmm format
|
||||
TAG=$(date +"%Y.%m.%d.%H%M")
|
||||
fi
|
||||
fi
|
||||
|
||||
# Parse command line arguments
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case $1 in
|
||||
--tag)
|
||||
TAG="$2"
|
||||
shift 2
|
||||
;;
|
||||
--registry)
|
||||
REGISTRY="$2"
|
||||
shift 2
|
||||
;;
|
||||
--push)
|
||||
PUSH=true
|
||||
shift
|
||||
;;
|
||||
--image-name)
|
||||
IMAGE_NAME="$2"
|
||||
shift 2
|
||||
;;
|
||||
*)
|
||||
echo "Unknown option: $1"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
# Determine the full image name
|
||||
if [ -n "$REGISTRY" ]; then
|
||||
FULL_IMAGE_NAME="$REGISTRY/$IMAGE_NAME"
|
||||
else
|
||||
FULL_IMAGE_NAME="$IMAGE_NAME"
|
||||
fi
|
||||
|
||||
# Display build information
|
||||
echo -e "\e[32mBuilding Docker image: $IMAGE_NAME\e[0m"
|
||||
echo -e "\e[32mTag: $TAG\e[0m"
|
||||
if [ -n "$REGISTRY" ]; then
|
||||
echo -e "\e[32mRegistry: $REGISTRY\e[0m"
|
||||
fi
|
||||
|
||||
# Check if Docker is available
|
||||
if ! command -v docker &> /dev/null; then
|
||||
echo -e "\e[31mDocker is not available. Please install Docker and try again.\e[0m"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Build the Docker image
|
||||
echo -e "\e[36mBuilding image: $FULL_IMAGE_NAME:$TAG\e[0m"
|
||||
|
||||
# Navigate to the root directory (two levels up from the script location)
|
||||
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
|
||||
|
||||
# Build the Docker image
|
||||
if ! docker build -t "$FULL_IMAGE_NAME:$TAG" -f "$(dirname "${BASH_SOURCE[0]}")/Dockerfile" "$ROOT_DIR"; then
|
||||
echo -e "\e[31mDocker build failed\e[0m"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo -e "\e[32mSuccessfully built image: $FULL_IMAGE_NAME:$TAG\e[0m"
|
||||
|
||||
# Push the image if requested
|
||||
if [ "$PUSH" = true ]; then
|
||||
echo -e "\e[36mPushing image to registry: $FULL_IMAGE_NAME:$TAG\e[0m"
|
||||
|
||||
if ! docker push "$FULL_IMAGE_NAME:$TAG"; then
|
||||
echo -e "\e[31mDocker push failed\e[0m"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo -e "\e[32mSuccessfully pushed image: $FULL_IMAGE_NAME:$TAG\e[0m"
|
||||
fi
|
||||
@@ -1,9 +1,10 @@
|
||||
services:
|
||||
app:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile
|
||||
container_name: ad-management-api
|
||||
context: ../../
|
||||
dockerfile: iac/docker/Dockerfile
|
||||
image: ActiveDirectoryManager:${VERSION:-latest}
|
||||
container_name: ActiveDirectoryManager-api
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "5000:5000"
|
||||
@@ -34,7 +35,7 @@ services:
|
||||
|
||||
postgres:
|
||||
image: postgres:15-alpine
|
||||
container_name: ad-management-postgres
|
||||
container_name: ActiveDirectoryManager-postgres
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
|
||||
@@ -55,7 +56,7 @@ services:
|
||||
|
||||
redis:
|
||||
image: redis:7-alpine
|
||||
container_name: ad-management-redis
|
||||
container_name: ActiveDirectoryManager-redis
|
||||
restart: unless-stopped
|
||||
command: redis-server --appendonly yes
|
||||
volumes:
|
||||
@@ -76,4 +77,4 @@ networks:
|
||||
|
||||
volumes:
|
||||
postgres-data:
|
||||
redis-data:
|
||||
redis-data:
|
||||
@@ -0,0 +1,14 @@
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: ad-management-config
|
||||
namespace: ad-management
|
||||
data:
|
||||
NODE_ENV: "production"
|
||||
PORT: "5000"
|
||||
BASE_URL: "https://ad-management.example.com"
|
||||
DEFAULT_ADMIN_USERNAME: "admin"
|
||||
DEFAULT_ADMIN_FULLNAME: "System Administrator"
|
||||
DISABLE_REGISTRATION: "false"
|
||||
POSTGRES_DB: "admgr"
|
||||
POSTGRES_USER: "postgres"
|
||||
@@ -0,0 +1,73 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: ad-management
|
||||
namespace: ad-management
|
||||
spec:
|
||||
replicas: 2
|
||||
selector:
|
||||
matchLabels:
|
||||
app: ad-management
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: ad-management
|
||||
spec:
|
||||
containers:
|
||||
- name: activedirectorymanager
|
||||
image: ActiveDirectoryManager:2025.05.21.1430
|
||||
imagePullPolicy: Always
|
||||
ports:
|
||||
- containerPort: 5000
|
||||
name: http
|
||||
envFrom:
|
||||
- configMapRef:
|
||||
name: ad-management-config
|
||||
- secretRef:
|
||||
name: ad-management-secrets
|
||||
env:
|
||||
- name: REDIS_HOST
|
||||
value: "redis"
|
||||
- name: REDIS_PORT
|
||||
value: "6379"
|
||||
- name: POSTGRES_HOST
|
||||
value: "postgres"
|
||||
- name: POSTGRES_PORT
|
||||
value: "5432"
|
||||
resources:
|
||||
requests:
|
||||
memory: "256Mi"
|
||||
cpu: "100m"
|
||||
limits:
|
||||
memory: "512Mi"
|
||||
cpu: "300m"
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /api/health
|
||||
port: http
|
||||
initialDelaySeconds: 30
|
||||
periodSeconds: 10
|
||||
timeoutSeconds: 5
|
||||
failureThreshold: 3
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: /api/health
|
||||
port: http
|
||||
initialDelaySeconds: 5
|
||||
periodSeconds: 5
|
||||
timeoutSeconds: 3
|
||||
failureThreshold: 1
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: ad-management
|
||||
namespace: ad-management
|
||||
spec:
|
||||
selector:
|
||||
app: ad-management
|
||||
ports:
|
||||
- port: 80
|
||||
targetPort: 5000
|
||||
name: http
|
||||
type: ClusterIP
|
||||
@@ -0,0 +1,26 @@
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: ad-management-ingress
|
||||
namespace: ad-management
|
||||
annotations:
|
||||
kubernetes.io/ingress.class: "nginx"
|
||||
cert-manager.io/cluster-issuer: "letsencrypt-prod"
|
||||
nginx.ingress.kubernetes.io/ssl-redirect: "true"
|
||||
nginx.ingress.kubernetes.io/proxy-body-size: "50m"
|
||||
spec:
|
||||
tls:
|
||||
- hosts:
|
||||
- ad-management.example.com
|
||||
secretName: ad-management-tls
|
||||
rules:
|
||||
- host: ad-management.example.com
|
||||
http:
|
||||
paths:
|
||||
- path: /
|
||||
pathType: Prefix
|
||||
backend:
|
||||
service:
|
||||
name: ad-management
|
||||
port:
|
||||
name: http
|
||||
@@ -0,0 +1,13 @@
|
||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
|
||||
namespace: ad-management
|
||||
|
||||
resources:
|
||||
- namespace.yaml
|
||||
- configmap.yaml
|
||||
- secrets.yaml
|
||||
- postgres.yaml
|
||||
- redis.yaml
|
||||
- deployment.yaml
|
||||
- ingress.yaml
|
||||
@@ -0,0 +1,6 @@
|
||||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
name: ad-management
|
||||
labels:
|
||||
name: ad-management
|
||||
@@ -0,0 +1,89 @@
|
||||
apiVersion: apps/v1
|
||||
kind: StatefulSet
|
||||
metadata:
|
||||
name: postgres
|
||||
namespace: ad-management
|
||||
spec:
|
||||
serviceName: postgres
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: postgres
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: postgres
|
||||
spec:
|
||||
containers:
|
||||
- name: postgres
|
||||
image: postgres:15-alpine
|
||||
ports:
|
||||
- containerPort: 5432
|
||||
name: postgres
|
||||
env:
|
||||
- name: POSTGRES_DB
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
name: ad-management-config
|
||||
key: POSTGRES_DB
|
||||
- name: POSTGRES_USER
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
name: ad-management-config
|
||||
key: POSTGRES_USER
|
||||
- name: POSTGRES_PASSWORD
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: ad-management-secrets
|
||||
key: POSTGRES_PASSWORD
|
||||
volumeMounts:
|
||||
- name: postgres-data
|
||||
mountPath: /var/lib/postgresql/data
|
||||
resources:
|
||||
requests:
|
||||
memory: "256Mi"
|
||||
cpu: "100m"
|
||||
limits:
|
||||
memory: "1Gi"
|
||||
cpu: "500m"
|
||||
livenessProbe:
|
||||
exec:
|
||||
command:
|
||||
- pg_isready
|
||||
- -U
|
||||
- postgres
|
||||
initialDelaySeconds: 30
|
||||
periodSeconds: 10
|
||||
timeoutSeconds: 5
|
||||
failureThreshold: 3
|
||||
readinessProbe:
|
||||
exec:
|
||||
command:
|
||||
- pg_isready
|
||||
- -U
|
||||
- postgres
|
||||
initialDelaySeconds: 5
|
||||
periodSeconds: 5
|
||||
timeoutSeconds: 3
|
||||
failureThreshold: 1
|
||||
volumeClaimTemplates:
|
||||
- metadata:
|
||||
name: postgres-data
|
||||
spec:
|
||||
accessModes: [ "ReadWriteOnce" ]
|
||||
resources:
|
||||
requests:
|
||||
storage: 10Gi
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: postgres
|
||||
namespace: ad-management
|
||||
spec:
|
||||
selector:
|
||||
app: postgres
|
||||
ports:
|
||||
- port: 5432
|
||||
targetPort: 5432
|
||||
clusterIP: None # Headless service for StatefulSet
|
||||
@@ -0,0 +1,71 @@
|
||||
apiVersion: apps/v1
|
||||
kind: StatefulSet
|
||||
metadata:
|
||||
name: redis
|
||||
namespace: ad-management
|
||||
spec:
|
||||
serviceName: redis
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: redis
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: redis
|
||||
spec:
|
||||
containers:
|
||||
- name: redis
|
||||
image: redis:7-alpine
|
||||
ports:
|
||||
- containerPort: 6379
|
||||
name: redis
|
||||
volumeMounts:
|
||||
- name: redis-data
|
||||
mountPath: /data
|
||||
resources:
|
||||
requests:
|
||||
memory: "128Mi"
|
||||
cpu: "50m"
|
||||
limits:
|
||||
memory: "256Mi"
|
||||
cpu: "200m"
|
||||
livenessProbe:
|
||||
exec:
|
||||
command:
|
||||
- redis-cli
|
||||
- ping
|
||||
initialDelaySeconds: 30
|
||||
periodSeconds: 10
|
||||
timeoutSeconds: 5
|
||||
failureThreshold: 3
|
||||
readinessProbe:
|
||||
exec:
|
||||
command:
|
||||
- redis-cli
|
||||
- ping
|
||||
initialDelaySeconds: 5
|
||||
periodSeconds: 5
|
||||
timeoutSeconds: 3
|
||||
failureThreshold: 1
|
||||
volumeClaimTemplates:
|
||||
- metadata:
|
||||
name: redis-data
|
||||
spec:
|
||||
accessModes: [ "ReadWriteOnce" ]
|
||||
resources:
|
||||
requests:
|
||||
storage: 1Gi
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: redis
|
||||
namespace: ad-management
|
||||
spec:
|
||||
selector:
|
||||
app: redis
|
||||
ports:
|
||||
- port: 6379
|
||||
targetPort: 6379
|
||||
clusterIP: None # Headless service for StatefulSet
|
||||
@@ -0,0 +1,14 @@
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: ad-management-secrets
|
||||
namespace: ad-management
|
||||
type: Opaque
|
||||
data:
|
||||
# These are example values. In production, replace with your own base64-encoded secrets
|
||||
# Example: echo -n "your-secret-value" | base64
|
||||
JWT_SECRET: Y2hhbmdlLXRoaXMtaW4tcHJvZHVjdGlvbg==
|
||||
SESSION_SECRET: Y2hhbmdlLXRoaXMtaW4tcHJvZHVjdGlvbg==
|
||||
DEFAULT_ADMIN_PASSWORD: cGFzc3dvcmQ=
|
||||
DEFAULT_ADMIN_EMAIL: YWRtaW5AZXhhbXBsZS5jb20=
|
||||
POSTGRES_PASSWORD: cG9zdGdyZXM=
|
||||
@@ -0,0 +1,40 @@
|
||||
# PowerShell script to update the Kubernetes deployment with the current version
|
||||
|
||||
# Get the directory of this script
|
||||
$scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
|
||||
$parentDir = Split-Path -Parent $scriptDir
|
||||
|
||||
# Read the version from version.txt
|
||||
$versionFile = Join-Path $parentDir "version.txt"
|
||||
if (-not (Test-Path $versionFile)) {
|
||||
Write-Host "Error: version.txt not found at $versionFile" -ForegroundColor Red
|
||||
exit 1
|
||||
}
|
||||
|
||||
$version = Get-Content $versionFile -Raw
|
||||
$version = $version.Trim()
|
||||
Write-Host "Using version: $version" -ForegroundColor Cyan
|
||||
|
||||
# Update the deployment.yaml file
|
||||
$deploymentFile = Join-Path $scriptDir "deployment.yaml"
|
||||
if (-not (Test-Path $deploymentFile)) {
|
||||
Write-Host "Error: deployment.yaml not found at $deploymentFile" -ForegroundColor Red
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Read the deployment file
|
||||
$content = Get-Content $deploymentFile -Raw
|
||||
|
||||
# Replace the image version
|
||||
$pattern1 = 'image: ActiveDirectoryManager:[0-9]{4}\.[0-9]{2}\.[0-9]{2}\.[0-9]{4}'
|
||||
$replacement1 = "image: ActiveDirectoryManager:$version"
|
||||
$content = $content -replace $pattern1, $replacement1
|
||||
|
||||
$pattern2 = 'image: ActiveDirectoryManager:latest'
|
||||
$replacement2 = "image: ActiveDirectoryManager:$version"
|
||||
$content = $content -replace $pattern2, $replacement2
|
||||
|
||||
# Write the updated content back to the file
|
||||
$content | Set-Content $deploymentFile
|
||||
|
||||
Write-Host "Updated deployment.yaml with version $version" -ForegroundColor Green
|
||||
@@ -0,0 +1,36 @@
|
||||
#!/bin/bash
|
||||
# Script to update the Kubernetes deployment with the current version
|
||||
|
||||
# Get the directory of this script
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
PARENT_DIR="$(dirname "$SCRIPT_DIR")"
|
||||
|
||||
# Read the version from version.txt
|
||||
VERSION_FILE="$PARENT_DIR/version.txt"
|
||||
if [ ! -f "$VERSION_FILE" ]; then
|
||||
echo "Error: version.txt not found at $VERSION_FILE"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
VERSION=$(cat "$VERSION_FILE" | tr -d '[:space:]')
|
||||
echo "Using version: $VERSION"
|
||||
|
||||
# Update the deployment.yaml file
|
||||
DEPLOYMENT_FILE="$SCRIPT_DIR/deployment.yaml"
|
||||
if [ ! -f "$DEPLOYMENT_FILE" ]; then
|
||||
echo "Error: deployment.yaml not found at $DEPLOYMENT_FILE"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Use sed to replace the image version
|
||||
if [[ "$OSTYPE" == "darwin"* ]]; then
|
||||
# macOS requires a different sed syntax
|
||||
sed -i '' "s|image: ActiveDirectoryManager:[0-9]\{4\}\.[0-9]\{2\}\.[0-9]\{2\}\.[0-9]\{4\}|image: ActiveDirectoryManager:$VERSION|g" "$DEPLOYMENT_FILE"
|
||||
sed -i '' "s|image: ActiveDirectoryManager:latest|image: ActiveDirectoryManager:$VERSION|g" "$DEPLOYMENT_FILE"
|
||||
else
|
||||
# Linux
|
||||
sed -i "s|image: ActiveDirectoryManager:[0-9]\{4\}\.[0-9]\{2\}\.[0-9]\{2\}\.[0-9]\{4\}|image: ActiveDirectoryManager:$VERSION|g" "$DEPLOYMENT_FILE"
|
||||
sed -i "s|image: ActiveDirectoryManager:latest|image: ActiveDirectoryManager:$VERSION|g" "$DEPLOYMENT_FILE"
|
||||
fi
|
||||
|
||||
echo "Updated deployment.yaml with version $VERSION"
|
||||
@@ -0,0 +1,24 @@
|
||||
# PowerShell script to update version and apply it to all components
|
||||
|
||||
# Get the directory of this script
|
||||
$scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
|
||||
|
||||
# Update version.txt with current date/time
|
||||
Write-Host "Updating version.txt..." -ForegroundColor Cyan
|
||||
& "$scriptDir\update-version.ps1"
|
||||
|
||||
# Read the new version
|
||||
$version = Get-Content "$scriptDir\version.txt" -Raw
|
||||
$version = $version.Trim()
|
||||
Write-Host "New version: $version" -ForegroundColor Green
|
||||
|
||||
# Update Kubernetes deployment
|
||||
Write-Host "Updating Kubernetes deployment..." -ForegroundColor Cyan
|
||||
& "$scriptDir\kubernetes\update-deployment-version.ps1"
|
||||
|
||||
Write-Host "Version update complete. New version: $version" -ForegroundColor Green
|
||||
Write-Host ""
|
||||
Write-Host "Next steps:" -ForegroundColor Yellow
|
||||
Write-Host "1. Build Docker image: cd $scriptDir\docker; .\build.ps1" -ForegroundColor Yellow
|
||||
Write-Host "2. Push Docker image: cd $scriptDir\docker; .\build.ps1 -push" -ForegroundColor Yellow
|
||||
Write-Host "3. Deploy to Kubernetes: cd $scriptDir\kubernetes; kubectl apply -k ." -ForegroundColor Yellow
|
||||
@@ -0,0 +1,24 @@
|
||||
#!/bin/bash
|
||||
# Comprehensive script to update version and apply it to all components
|
||||
|
||||
# Get the directory of this script
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
|
||||
# Update version.txt with current date/time
|
||||
echo "Updating version.txt..."
|
||||
"$SCRIPT_DIR/update-version.sh"
|
||||
|
||||
# Read the new version
|
||||
VERSION=$(cat "$SCRIPT_DIR/version.txt" | tr -d '[:space:]')
|
||||
echo "New version: $VERSION"
|
||||
|
||||
# Update Kubernetes deployment
|
||||
echo "Updating Kubernetes deployment..."
|
||||
"$SCRIPT_DIR/kubernetes/update-deployment-version.sh"
|
||||
|
||||
echo "Version update complete. New version: $VERSION"
|
||||
echo ""
|
||||
echo "Next steps:"
|
||||
echo "1. Build Docker image: cd $SCRIPT_DIR/docker && ./build.sh"
|
||||
echo "2. Push Docker image: cd $SCRIPT_DIR/docker && ./build.sh --push"
|
||||
echo "3. Deploy to Kubernetes: cd $SCRIPT_DIR/kubernetes && kubectl apply -k ."
|
||||
@@ -0,0 +1,10 @@
|
||||
# PowerShell script to update the version.txt file with the current date and time
|
||||
|
||||
# Generate version in yyyy.MM.dd.HHmm format
|
||||
$version = Get-Date -Format "yyyy.MM.dd.HHmm"
|
||||
|
||||
# Update version.txt
|
||||
$versionFile = Join-Path $PSScriptRoot "version.txt"
|
||||
$version | Out-File -FilePath $versionFile -NoNewline
|
||||
|
||||
Write-Host "Version updated to: $version"
|
||||
@@ -0,0 +1,10 @@
|
||||
#!/bin/bash
|
||||
# Script to update the version.txt file with the current date and time
|
||||
|
||||
# Generate version in yyyy.MM.dd.HHmm format
|
||||
VERSION=$(date +"%Y.%m.%d.%H%M")
|
||||
|
||||
# Update version.txt
|
||||
echo "$VERSION" > "$(dirname "$0")/version.txt"
|
||||
|
||||
echo "Version updated to: $VERSION"
|
||||
@@ -0,0 +1 @@
|
||||
2025.05.21.1430
|
||||
+1177
-206
File diff suppressed because it is too large
Load Diff
+1630
-536
File diff suppressed because it is too large
Load Diff
+95
-16
@@ -35,6 +35,32 @@ const swaggerOptions = {
|
||||
description: "API base URL",
|
||||
},
|
||||
],
|
||||
tags: [
|
||||
{
|
||||
name: "LDAP Connections",
|
||||
description: "Operations for managing LDAP connections"
|
||||
},
|
||||
{
|
||||
name: "AD Users",
|
||||
description: "Operations for managing Active Directory users"
|
||||
},
|
||||
{
|
||||
name: "AD Groups",
|
||||
description: "Operations for managing Active Directory groups"
|
||||
},
|
||||
{
|
||||
name: "AD Computers",
|
||||
description: "Operations for managing Active Directory computers"
|
||||
},
|
||||
{
|
||||
name: "AD Organizational Units",
|
||||
description: "Operations for managing Active Directory organizational units"
|
||||
},
|
||||
{
|
||||
name: "Active Directory",
|
||||
description: "General Active Directory operations including password management and account status"
|
||||
}
|
||||
],
|
||||
components: {
|
||||
securitySchemes: {
|
||||
bearerAuth: {
|
||||
@@ -299,7 +325,7 @@ const swaggerOptions = {
|
||||
id: { type: "integer" },
|
||||
action: { type: "string" },
|
||||
targetId: { type: "string" },
|
||||
details: {
|
||||
details: {
|
||||
type: "object",
|
||||
additionalProperties: true
|
||||
},
|
||||
@@ -308,6 +334,59 @@ const swaggerOptions = {
|
||||
connectionId: { type: "integer" }
|
||||
},
|
||||
},
|
||||
PasswordReset: {
|
||||
type: "object",
|
||||
required: ["userObjectGUID", "newPassword"],
|
||||
properties: {
|
||||
userObjectGUID: {
|
||||
type: "string",
|
||||
description: "The ObjectGUID of the user"
|
||||
},
|
||||
newPassword: {
|
||||
type: "string",
|
||||
description: "The new password for the user"
|
||||
},
|
||||
skipValidation: {
|
||||
type: "boolean",
|
||||
description: "Whether to skip password policy validation",
|
||||
default: false
|
||||
},
|
||||
requirePasswordChangeAtNextLogon: {
|
||||
type: "boolean",
|
||||
description: "Whether to require the user to change their password at next logon",
|
||||
default: true
|
||||
}
|
||||
}
|
||||
},
|
||||
EnableUserAccount: {
|
||||
type: "object",
|
||||
required: ["userObjectGUID", "enabled"],
|
||||
properties: {
|
||||
userObjectGUID: {
|
||||
type: "string",
|
||||
description: "The ObjectGUID of the user"
|
||||
},
|
||||
enabled: {
|
||||
type: "boolean",
|
||||
description: "Whether to enable or disable the account"
|
||||
}
|
||||
}
|
||||
},
|
||||
BulkEnableUserAccounts: {
|
||||
type: "object",
|
||||
required: ["userDNs", "enabled"],
|
||||
properties: {
|
||||
userDNs: {
|
||||
type: "array",
|
||||
items: { type: "string" },
|
||||
description: "Array of user distinguished names"
|
||||
},
|
||||
enabled: {
|
||||
type: "boolean",
|
||||
description: "Whether to enable or disable the accounts"
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
responses: {
|
||||
UnauthorizedError: {
|
||||
@@ -394,13 +473,13 @@ export function setupSwagger(app: Express) {
|
||||
// Mount at both paths for backward compatibility
|
||||
app.use("/api/docs", swaggerUi.serve, swaggerUi.setup(swaggerSpec, swaggerUiOptions));
|
||||
app.use("/api-docs", swaggerUi.serve, swaggerUi.setup(swaggerSpec, swaggerUiOptions));
|
||||
|
||||
|
||||
// Provide the JSON spec at multiple paths
|
||||
app.get("/api/swagger.json", (req, res) => {
|
||||
res.setHeader("Content-Type", "application/json");
|
||||
res.send(swaggerSpec);
|
||||
});
|
||||
|
||||
|
||||
app.get("/api-docs/swagger.json", (req, res) => {
|
||||
res.setHeader("Content-Type", "application/json");
|
||||
res.send(swaggerSpec);
|
||||
@@ -408,8 +487,8 @@ export function setupSwagger(app: Express) {
|
||||
|
||||
// Add download endpoint for the OpenAPI specification
|
||||
app.get("/api/docs/download", (req, res) => {
|
||||
const format = req.query.format?.toString().toLowerCase() || 'json';
|
||||
|
||||
const format = req.query.format?.toString().toLowerCase() ?? 'json';
|
||||
|
||||
if (format === 'json') {
|
||||
res.setHeader('Content-Disposition', 'attachment; filename=openapi-spec.json');
|
||||
res.setHeader('Content-Type', 'application/json');
|
||||
@@ -455,7 +534,7 @@ export function setupSwagger(app: Express) {
|
||||
</head>
|
||||
<body>
|
||||
<h1>Active Directory Management API - Advanced Usage Guide</h1>
|
||||
|
||||
|
||||
<h2>API Documentation</h2>
|
||||
<p>The complete API documentation is available at <a href="/api/docs">/api/docs</a>.</p>
|
||||
<p>You can also download the OpenAPI specification:</p>
|
||||
@@ -463,28 +542,28 @@ export function setupSwagger(app: Express) {
|
||||
<a href="/api/docs/download?format=json" class="btn">Download OpenAPI Spec (JSON)</a>
|
||||
<a href="/api/docs/download?format=yaml" class="btn">Download OpenAPI Spec (YAML)</a>
|
||||
</p>
|
||||
|
||||
|
||||
<h2>Query Parameters and Filtering</h2>
|
||||
<pre>${queryParamsInfo}</pre>
|
||||
|
||||
|
||||
<h2>Authentication</h2>
|
||||
<p>This API supports two authentication methods:</p>
|
||||
<ul>
|
||||
<li><strong>Session-based authentication</strong>: Used when accessing the API from the web interface.</li>
|
||||
<li><strong>API Token authentication</strong>: Used when accessing the API programmatically.</li>
|
||||
</ul>
|
||||
|
||||
|
||||
<h3>API Token Authentication</h3>
|
||||
<p>To authenticate using an API token, include the token in the Authorization header:</p>
|
||||
<pre>Authorization: Bearer YOUR_API_TOKEN</pre>
|
||||
|
||||
|
||||
<h2>Rate Limiting</h2>
|
||||
<p>The API has rate limiting in place to prevent abuse. The current limits are:</p>
|
||||
<ul>
|
||||
<li>100 requests per minute for authenticated users</li>
|
||||
<li>20 requests per minute for unauthenticated users</li>
|
||||
</ul>
|
||||
|
||||
|
||||
<h2>Error Handling</h2>
|
||||
<p>The API returns consistent error responses with the following structure:</p>
|
||||
<pre>{
|
||||
@@ -496,20 +575,20 @@ export function setupSwagger(app: Express) {
|
||||
}
|
||||
]
|
||||
}</pre>
|
||||
|
||||
|
||||
<h2>Example Usage</h2>
|
||||
<h3>Filter Users by Name</h3>
|
||||
<pre>GET /api/connections/1/ad-users?filter=displayName contains 'John'</pre>
|
||||
|
||||
|
||||
<h3>Select Specific Fields</h3>
|
||||
<pre>GET /api/connections/1/ad-users?select=id,displayName,email</pre>
|
||||
|
||||
|
||||
<h3>Pagination</h3>
|
||||
<pre>GET /api/connections/1/ad-users?top=10&skip=20</pre>
|
||||
|
||||
|
||||
<h3>Combining Parameters</h3>
|
||||
<pre>GET /api/connections/1/ad-users?filter=enabled eq true&select=id,displayName,email&orderBy=displayName asc&top=10</pre>
|
||||
|
||||
|
||||
<p>Return to <a href="/api/docs">API Documentation</a></p>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
+77
-27
@@ -19,48 +19,48 @@ export const PERMISSIONS = {
|
||||
CREATE_USERS: "create:users",
|
||||
UPDATE_USERS: "update:users",
|
||||
DELETE_USERS: "delete:users",
|
||||
|
||||
|
||||
// LDAP connections
|
||||
VIEW_LDAP_CONNECTIONS: "view:ldap_connections",
|
||||
CREATE_LDAP_CONNECTIONS: "create:ldap_connections",
|
||||
UPDATE_LDAP_CONNECTIONS: "update:ldap_connections",
|
||||
DELETE_LDAP_CONNECTIONS: "delete:ldap_connections",
|
||||
|
||||
|
||||
// Active Directory management
|
||||
VIEW_AD_USERS: "view:ad_users",
|
||||
CREATE_AD_USERS: "create:ad_users",
|
||||
UPDATE_AD_USERS: "update:ad_users",
|
||||
DELETE_AD_USERS: "delete:ad_users",
|
||||
MOVE_AD_USERS: "move:ad_users",
|
||||
|
||||
|
||||
VIEW_AD_GROUPS: "view:ad_groups",
|
||||
CREATE_AD_GROUPS: "create:ad_groups",
|
||||
UPDATE_AD_GROUPS: "update:ad_groups",
|
||||
DELETE_AD_GROUPS: "delete:ad_groups",
|
||||
MANAGE_GROUP_MEMBERSHIP: "manage:group_membership",
|
||||
|
||||
|
||||
VIEW_AD_OUS: "view:ad_ous",
|
||||
CREATE_AD_OUS: "create:ad_ous",
|
||||
UPDATE_AD_OUS: "update:ad_ous",
|
||||
DELETE_AD_OUS: "delete:ad_ous",
|
||||
|
||||
|
||||
VIEW_AD_COMPUTERS: "view:ad_computers",
|
||||
CREATE_AD_COMPUTERS: "create:ad_computers",
|
||||
UPDATE_AD_COMPUTERS: "update:ad_computers",
|
||||
DELETE_AD_COMPUTERS: "delete:ad_computers",
|
||||
MOVE_AD_COMPUTERS: "move:ad_computers",
|
||||
|
||||
|
||||
VIEW_AD_DOMAINS: "view:ad_domains",
|
||||
CREATE_AD_DOMAINS: "create:ad_domains",
|
||||
UPDATE_AD_DOMAINS: "update:ad_domains",
|
||||
DELETE_AD_DOMAINS: "delete:ad_domains",
|
||||
|
||||
|
||||
// Sites and Services management
|
||||
VIEW_AD_SITES: "view:ad_sites",
|
||||
CREATE_AD_SITES: "create:ad_sites",
|
||||
UPDATE_AD_SITES: "update:ad_sites",
|
||||
DELETE_AD_SITES: "delete:ad_sites",
|
||||
|
||||
|
||||
VIEW_AD_SUBNETS: "view:ad_subnets",
|
||||
CREATE_AD_SUBNETS: "create:ad_subnets",
|
||||
UPDATE_AD_SUBNETS: "update:ad_subnets",
|
||||
@@ -68,7 +68,7 @@ export const PERMISSIONS = {
|
||||
|
||||
// API Token management
|
||||
MANAGE_API_TOKENS: "manage:api_tokens",
|
||||
|
||||
|
||||
// Administrative functions
|
||||
MANAGE_ROLES: "manage:roles",
|
||||
SYSTEM_ADMIN: "admin:system",
|
||||
@@ -175,10 +175,10 @@ export const ldapConnections = pgTable("ldap_connections", {
|
||||
export const scheduleFrequencies = [
|
||||
"once",
|
||||
"minutely",
|
||||
"hourly",
|
||||
"daily",
|
||||
"weekly",
|
||||
"monthly",
|
||||
"hourly",
|
||||
"daily",
|
||||
"weekly",
|
||||
"monthly",
|
||||
"yearly"
|
||||
] as const;
|
||||
|
||||
@@ -234,7 +234,7 @@ export const dynamicGroupRules = pgTable("dynamic_group_rules", {
|
||||
|
||||
// Rule conditions (filter logic)
|
||||
export const dynamicGroupConditions = pgTable("dynamic_group_conditions", {
|
||||
id: serial("id").primaryKey(),
|
||||
id: serial("id").primaryKey(),
|
||||
ruleId: integer("rule_id").references(() => dynamicGroupRules.id, { onDelete: "cascade" }).notNull(),
|
||||
parentId: integer("parent_id").references(() => dynamicGroupConditions.id, { onDelete: "cascade" }),
|
||||
type: text("type").notNull(), // "condition", "group"
|
||||
@@ -498,6 +498,53 @@ export const removeFromGroupSchema = z.object({
|
||||
objectType: z.enum(["user", "computer"]),
|
||||
});
|
||||
|
||||
// Password management schemas
|
||||
export const resetPasswordSchema = z.object({
|
||||
userObjectGUID: z.string().min(1, "User ObjectGUID is required"),
|
||||
newPassword: z.string().min(8, "Password must be at least 8 characters long"),
|
||||
skipValidation: z.boolean().optional().default(false),
|
||||
requirePasswordChangeAtNextLogon: z.boolean().optional().default(true),
|
||||
});
|
||||
|
||||
export const enableUserAccountSchema = z.object({
|
||||
userObjectGUID: z.string().min(1, "User ObjectGUID is required"),
|
||||
enabled: z.boolean(),
|
||||
});
|
||||
|
||||
// Bulk operations schemas
|
||||
export const bulkEnableUserAccountsSchema = z.object({
|
||||
userDNs: z.array(z.string().min(1, "User DN is required")),
|
||||
enabled: z.boolean(),
|
||||
});
|
||||
|
||||
// Bulk operations schemas
|
||||
export const bulkMoveObjectsSchema = z.object({
|
||||
objectDNs: z.array(z.string().min(1, "Object DN is required")),
|
||||
targetOU: z.string().min(1, "Target OU is required"),
|
||||
});
|
||||
|
||||
export const bulkAddToGroupSchema = z.object({
|
||||
memberDNs: z.array(z.string().min(1, "Member DN is required")),
|
||||
groupDN: z.string().min(1, "Group DN is required"),
|
||||
});
|
||||
|
||||
export const bulkRemoveFromGroupSchema = z.object({
|
||||
memberDNs: z.array(z.string().min(1, "Member DN is required")),
|
||||
groupDN: z.string().min(1, "Group DN is required"),
|
||||
});
|
||||
|
||||
export const bulkEnableUserAccountsSchema = z.object({
|
||||
userDNs: z.array(z.string().min(1, "User DN is required")),
|
||||
enabled: z.boolean(),
|
||||
});
|
||||
|
||||
export const bulkUpdateAttributeSchema = z.object({
|
||||
objectDNs: z.array(z.string().min(1, "Object DN is required")),
|
||||
attributeName: z.string().min(1, "Attribute name is required"),
|
||||
attributeValue: z.union([z.string(), z.array(z.string()), z.null()]),
|
||||
operation: z.enum(["add", "replace", "delete"]).default("replace"),
|
||||
});
|
||||
|
||||
// ManagedBy operation schema is no longer needed as it's been replaced by object-specific PATCH endpoints
|
||||
|
||||
// Export types
|
||||
@@ -536,6 +583,9 @@ export type MoveComputer = z.infer<typeof moveComputerSchema>;
|
||||
export type MoveUser = z.infer<typeof moveUserSchema>;
|
||||
export type AddToGroup = z.infer<typeof addToGroupSchema>;
|
||||
export type RemoveFromGroup = z.infer<typeof removeFromGroupSchema>;
|
||||
export type ResetPassword = z.infer<typeof resetPasswordSchema>;
|
||||
export type EnableUserAccount = z.infer<typeof enableUserAccountSchema>;
|
||||
export type BulkEnableUserAccounts = z.infer<typeof bulkEnableUserAccountsSchema>;
|
||||
export type DynamicGroupRule = typeof dynamicGroupRules.$inferSelect;
|
||||
export type InsertDynamicGroupRule = z.infer<typeof insertDynamicGroupRuleSchema>;
|
||||
export type DynamicGroupCondition = typeof dynamicGroupConditions.$inferSelect;
|
||||
@@ -651,22 +701,22 @@ export const ldapAttributesRelations = relations(ldapAttributes, ({ one }) => ({
|
||||
}));
|
||||
|
||||
// Generate insertion schemas
|
||||
export const insertLdapFilterSchema = createInsertSchema(ldapFilters).omit({
|
||||
id: true,
|
||||
createdAt: true,
|
||||
export const insertLdapFilterSchema = createInsertSchema(ldapFilters).omit({
|
||||
id: true,
|
||||
createdAt: true,
|
||||
modifiedAt: true,
|
||||
currentVersion: true
|
||||
currentVersion: true
|
||||
});
|
||||
|
||||
export const insertLdapFilterRevisionSchema = createInsertSchema(ldapFilterRevisions).omit({
|
||||
id: true,
|
||||
createdAt: true
|
||||
export const insertLdapFilterRevisionSchema = createInsertSchema(ldapFilterRevisions).omit({
|
||||
id: true,
|
||||
createdAt: true
|
||||
});
|
||||
|
||||
export const insertLdapAttributeSchema = createInsertSchema(ldapAttributes).omit({
|
||||
id: true,
|
||||
createdAt: true,
|
||||
updatedAt: true
|
||||
export const insertLdapAttributeSchema = createInsertSchema(ldapAttributes).omit({
|
||||
id: true,
|
||||
createdAt: true,
|
||||
updatedAt: true
|
||||
});
|
||||
|
||||
// Export types
|
||||
@@ -678,8 +728,8 @@ export type LdapAttribute = typeof ldapAttributes.$inferSelect;
|
||||
export type InsertLdapAttribute = z.infer<typeof insertLdapAttributeSchema>;
|
||||
|
||||
// Audit log schema and types
|
||||
export const insertAuditLogSchema = createInsertSchema(auditLogs).omit({
|
||||
id: true,
|
||||
export const insertAuditLogSchema = createInsertSchema(auditLogs).omit({
|
||||
id: true,
|
||||
timestamp: true
|
||||
});
|
||||
export type AuditLog = typeof auditLogs.$inferSelect;
|
||||
|
||||
Reference in New Issue
Block a user