Table of Contents

Enterprise Best Practices

Production High Availability

# Kubernetes high availability deployment
apiVersion: apps/v1
kind: Deployment
metadata:
  name: authentik-server
spec:
  replicas: 3
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 1
      maxUnavailable: 0
  selector:
    matchLabels:
      app: authentik-server
  template:
    metadata:
      labels:
        app: authentik-server
    spec:
      containers:
      - name: authentik
        image: ghcr.io/goauthentik/server:2024.2.2
        command: ["ak"]
        args: ["server"]
        env:
        - name: AUTHENTIK_SECRET_KEY
          valueFrom:
            secretKeyRef:
              name: authentik-secret
              key: secret-key
        - name: AUTHENTIK_POSTGRESQL__HOST
          value: "postgres-cluster"
        - name: AUTHENTIK_REDIS__HOST
          value: "redis-cluster"
        ports:
        - containerPort: 9000
        - containerPort: 9443
        resources:
          requests:
            memory: "512Mi"
            cpu: "500m"
          limits:
            memory: "1Gi"
            cpu: "1000m"
        livenessProbe:
          httpGet:
            path: /-/health/live/
            port: 9000
          initialDelaySeconds: 30
          periodSeconds: 30
        readinessProbe:
          httpGet:
            path: /-/health/ready/
            port: 9000
          initialDelaySeconds: 10
          periodSeconds: 10

Performance Optimization

function Optimize-AuthentikPerformance
{
    param(
        [int]$WebWorkers = 4,
        [int]$BackgroundWorkers = 2,
        [string]$RedisMaxMemory = "256mb",
        [string]$PostgresSharedBuffers = "256MB"
    )
    
    $optimizations = @{
        web_server = @{
            workers = $WebWorkers
            worker_connections = 1000
            keepalive_timeout = 65
            client_max_body_size = "25M"
        }
        
        background_workers = @{
            count = $BackgroundWorkers
            max_tasks_per_child = 1000
            pool_pre_ping = $true
        }
        
        redis = @{
            maxmemory = $RedisMaxMemory
            maxmemory_policy = "allkeys-lru"
            save_intervals = @("900 1", "300 10", "60 10000")
        }
        
        postgresql = @{
            shared_buffers = $PostgresSharedBuffers
            effective_cache_size = "1GB"
            maintenance_work_mem = "64MB"
            max_connections = 200
        }
    }
    
    Write-Host "Performance optimization recommendations:" -ForegroundColor Cyan
    $optimizations | ConvertTo-Json -Depth 3
    
    return $optimizations
}

Automation and Scripting

PowerShell Module for Authentik Management

# AuthentikManagement.psm1
class AuthentikClient
{
    [string]$BaseUrl
    [string]$ApiToken
    [hashtable]$Headers
    
    AuthentikClient([string]$url, [string]$token)
    {
        $this.BaseUrl = $url.TrimEnd('/')
        $this.ApiToken = $token
        $this.Headers = @{
            'Authorization' = "Bearer $token"
            'Content-Type' = 'application/json'
        }
    }
    
    [object] InvokeApi([string]$endpoint, [string]$method = 'GET', [object]$body = $null)
    {
        $uri = "$($this.BaseUrl)$endpoint"
        $params = @{
            Uri = $uri
            Method = $method
            Headers = $this.Headers
        }
        
        if ($body)
        {
            $params.Body = $body | ConvertTo-Json -Depth 10
        }
        
        try
        {
            return Invoke-RestMethod @params
        }
        catch
        {
            Write-Error "API call failed: $($_.Exception.Message)"
            return $null
        }
    }
    
    [array] GetUsers([string]$search = "")
    {
        $endpoint = "/api/v3/core/users/"
        if ($search) { $endpoint += "?search=$search" }
        
        $response = $this.InvokeApi($endpoint)
        return $response.results
    }
    
    [object] CreateUser([hashtable]$userData)
    {
        return $this.InvokeApi("/api/v3/core/users/", "POST", $userData)
    }
    
    [array] GetApplications()
    {
        $response = $this.InvokeApi("/api/v3/core/applications/")
        return $response.results
    }
    
    [object] CreateApplication([hashtable]$appData)
    {
        return $this.InvokeApi("/api/v3/core/applications/", "POST", $appData)
    }
}

function Connect-Authentik
{
    param(
        [Parameter(Mandatory)]
        [string]$Url,
        [Parameter(Mandatory)]
        [string]$ApiToken
    )
    
    return [AuthentikClient]::new($Url, $ApiToken)
}

function New-AuthentikApplication
{
    param(
        [Parameter(Mandatory)]
        [AuthentikClient]$Client,
        [Parameter(Mandatory)]
        [string]$Name,
        [Parameter(Mandatory)]
        [string]$Slug,
        [string]$Provider,
        [string]$Group = "",
        [hashtable]$PolicyBindings = @{}
    )
    
    $appData = @{
        name = $Name
        slug = $Slug
        provider = $Provider
        group = $Group
        policy_engine_mode = "any"
        meta_description = "Created via PowerShell automation"
    }
    
    if ($PolicyBindings.Count -gt 0)
    {
        $appData.policy_bindings = $PolicyBindings
    }
    
    return $Client.CreateApplication($appData)
}

Export-ModuleMember -Function Connect-Authentik, New-AuthentikApplication

Bulk Operations Script

function Import-UsersFromCsv
{
    param(
        [Parameter(Mandatory)]
        [string]$CsvPath,
        [Parameter(Mandatory)]
        [AuthentikClient]$AuthentikClient,
        [string[]]$DefaultGroups = @(),
        [switch]$SendWelcomeEmail
    )
    
    if (-not (Test-Path $CsvPath))
    {
        throw "CSV file not found: $CsvPath"
    }
    
    $users = Import-Csv -Path $CsvPath
    $results = @()
    
    Write-Host "Importing $($users.Count) users from CSV..." -ForegroundColor Cyan
    
    foreach ($user in $users)
    {
        try
        {
            $userData = @{
                username = $user.Username
                email = $user.Email
                first_name = $user.FirstName
                last_name = $user.LastName
                is_active = $true
                groups = $DefaultGroups + ($user.Groups -split ',')
            }
            
            $result = $AuthentikClient.CreateUser($userData)
            
            if ($result)
            {
                Write-Host "✓ Created user: $($user.Username)" -ForegroundColor Green
                $results += @{
                    Username = $user.Username
                    Status = "Success"
                    UserId = $result.pk
                }
                
                if ($SendWelcomeEmail)
                {
                    # Send welcome email logic here
                }
            }
            else
            {
                Write-Warning "Failed to create user: $($user.Username)"
                $results += @{
                    Username = $user.Username
                    Status = "Failed"
                    Error = "API call failed"
                }
            }
        }
        catch
        {
            Write-Error "Error creating user $($user.Username): $($_.Exception.Message)"
            $results += @{
                Username = $user.Username
                Status = "Error"
                Error = $_.Exception.Message
            }
        }
    }
    
    # Summary
    $successful = ($results | Where-Object { $_.Status -eq "Success" }).Count
    $failed = $results.Count - $successful
    
    Write-Host "`nImport Summary:" -ForegroundColor Cyan
    Write-Host "  Total users processed: $($results.Count)" -ForegroundColor White
    Write-Host "  Successful: $successful" -ForegroundColor Green
    Write-Host "  Failed: $failed" -ForegroundColor Red
    
    return $results
}

◄ Troubleshooting · Authentik Overview