A Dynamic DNS management system with Azure DNS integration, featuring automated record synchronization, TTL-based expiration, and containerized deployment support.
- Token-based Authentication: Secure authentication using Authorization Bearer tokens
- Account Creation: Generate unique tokens for API access
- Login System: Email and token-based authentication
- CRUD Operations: Create, read, update, and delete DNS records
- Real-time Sync: Automatic synchronization with Azure DNS zones
- Status Tracking: Records lifecycle:
added→active→refreshed→inactive - TTL Expiration: Automatic record expiration based on configurable TTL
- Hostname Validation: Global uniqueness validation across all users
- Soft Delete: Records marked inactive before Azure DNS cleanup
- 5-Minute Sync Cycle: Automated background service for DNS operations
- Activates new/updated records in Azure DNS
- Expires stale records based on TTL
- Deletes inactive records from Azure DNS
- Hostname Change Handling: Automatic cleanup of old DNS records when hostname changes
- Azure DNS Zone Management: Direct integration with Azure DNS
- Managed Identity Support: Secure authentication using Azure Managed Identity
- A Record Management: Create, update, and delete DNS A records with 1-hour TTL
- Authorization Headers: Industry-standard Bearer token authentication
- Token Isolation: Per-user token with record isolation
- Secure Defaults: Non-root container user, HTTPS redirection
- React 18 with Vite
- Material-UI (MUI)
- React Router for navigation
- Modern responsive design
- Configurable domain visualization
- ASP.NET Core 9.0 Minimal APIs
- Entity Framework Core with Azure SQL Database
- Passwordless authentication via Azure Entra ID (Managed Identity)
- Azure SDK for DNS management (Azure.ResourceManager.Dns)
- Background services with PeriodicTimer
- Scalar API documentation (OpenAPI)
- EF Core Migrations for schema management
- Docker containerization
- Azure Container Apps ready
- Kubernetes deployment manifests
- Managed Identity authentication
- .NET 9.0 SDK
- Node.js and npm
- Azure subscription (for DNS and database)
- Azure DNS zone configured
- Azure SQL Database configured with Entra ID authentication
- Azure CLI installed and authenticated (
az login)
{Server=tcp:your-server.database.windows.net,1433;Initial Catalog=your-database;Authentication=Active Directory Default;Encrypt=True;TrustServerCertificate=False;Connection Timeout=30;"
},
"RecordTTL": 3600,
"AzureDns": {
"ZoneName": "your-domain.com",
"ResourceGroupName": "your-resource-group",
"SubscriptionId": "your-subscription-id"
}
}Note: The connection string uses passwordless authentication. No credentials are stored in configuration files. }
#### Frontend Configuration (`frontend/src/config.js`)
```javascript
export const config = {
domainName: 'your-domain.com',
apiUrl: 'http://localhost:5000'
};
First Time Setup:
- Sign in to Azure:
az login- Create SQL database user (run in Azure Portal Query Editor on your database):
CREATE USER [your-email@domain.com] FROM EXTERNAL PROVIDER;
ALTER ROLE db_datareader ADD MEMBER [your-email@domain.com];
ALTER ROLE db_datawriter ADD MEMBER [your-email@domain.com];
ALTER ROLE db_ddladmin ADD MEMBER [your-email@domain.com];
GO- Create and apply database migrations:
cd backend
dotnet restore
dotnet ef migrations add InitialCreate
dotnet ef database updateRun the Application:
cd backend
dotnet restore
dotnet runThe application uses passwordless authentication via Azure Entra ID (formerly Azure Active Directory) for both Azure SQL Database and Azure DNS operations using DefaultAzureCredential.
Local Development:
# Sign in to Azure (uses your credentials for both SQL and DNS)
az login
# Verify you're signed in
az account showAzure SQL Database Setup:
Quick steps:
- Create database user for local development (your Azure account)
- For production: Enable managed identity and create SQL user for the identity
- Grant roles:
db_datareader,db_datawriter,db_ddladmin
Azure DNS Setup:
Enable system-assigned managed identity and grant DNS Zone Contributor role:
# For Azure Container Apps
az containerapp identity assign \
--name <app-name> \
--resource-group <resource-group> \
--sConnectionStrings__DefaultConnection="Server=tcp:your-server.database.windows.net,1433;Initial Catalog=your-database;Authentication=Active Directory Default;Encrypt=True;" \
-e AzureDns__ZoneName=your-domain.com \
-e AzureDns__ResourceGroupName=your-rg \
-e AzureDns__SubscriptionId=your-sub-id \
ddns-backend:latestNote: When running in Azure (Container Apps, AKS, App Service), managed identity is automatically discovered. No additional environment variables needed for authentication.PATCH /api/dns/{id}` - Update DNS record (requires Authorization header)
DELETE /api/dns/{id}- Delete DNS record (requires Authorization header)POST /api/dns/refresh- Refresh record timestamp (accepts Authorization header OR body token)GET /scalar/v1- API documentation (development only) System-assigned managed identity configuration- Azure SQL Database user creation with Object ID
- DNS Zone Contributor role assignment
Quick Setup Commands:
# Enable managed identity
az containerapp identity assign --name <app> --resource-group <rg> --system-assigned
# Get the principal ID
PRINCIPAL_ID=$(az containerapp identity show --name <app> --resource-group <rg> --query principalId -o tsv)
# Create SQL user (run in Azure Portal Query Editor)
CREATE USER [your-app-name] FROM EXTERNAL PROVIDER WITH OBJECT_ID = '<principal-id-guid>';
ALTER ROLE db_datareader ADD MEMBER [your-app-name];
ALTER ROLE db_datawriter ADD MEMBER [your-app-name];
ALTER ROLE db_ddladmin ADD MEMBER [your-app-name];
GO
# Grant DNS permissions
az role assignment create \
--assignee $PRINCIPAL_ID \
--role "DNS Zone Contributor" \
--scope /subscriptions/<sub>/resourceGroups/<rg>/providers/Microsoft.Network/dnszones/<zone>cd frontend
npm install
npm run devThe frontend starts at http://localhost:5173
Local Development:
az loginAzure Container Apps: Enable system-assigned managed identity and grant DNS Zone Contributor role:
az role assignment create \
--assignee <managed-identity-principal-id> \
--role "DNS Zone Contributor" \
--scope /subscriptions/{subscription-id}/resourceGroups/{rg}/providers/Microsoft.Network/dnszones/{zone-name}cd backend
docker build -t ddns-backend:latest .docker run -p 8080:8080 \
-e ASPNETCORE_ENVIRONMENT=Production \
-e AzureDns__ZoneName=your-domain.com \
-e AzureDns__ResourceGroupName=your-rg \
-e AzureDns__SubscriptionId=your-sub-id \
ddns-backend:latestSee infrastructure/README.md for complete deployment instructions including:
- Container registry setup
- Container Apps environment creation
- Managed identity configuration
- DNS role assignment
User creates record (status: "added")
↓
Background service (5 min)
↓
Create in Azure DNS → status: "active"
↓
User updates record (status: "updated")
↓
Background service
↓
Update Azure DNS → status: "active"
↓
TTL expires (no refresh)
↓
Background service → status: "inactive"
↓
Background service
↓
Delete from Azure DNS → Remove from DB
EvPasswordless Authentication: No credentials in configuration files
✅ Azure Entra ID Integration: Managed Identity for Azure SQL and DNS
✅ Authorization Bearer Tokens: Industry-standard API authentication
✅ Token Validation: All protected endpoints validated
✅ Encrypted Connections: TLS for Azure SQL Database
✅ Non-root Container User: Security-hardened Docker images
✅ CORS Restricted: Frontend origin whitelisting
✅ Soft Delete: Confirmation before permanent removal
✅ Principle of Least Privilege: Granular role assignments
ddns/
├── backend/
│ ├── Program.cs # API endpoints + startup
│ ├── AppDbContext.cs # EF Core context
│ ├── User.cs # User entity
│ ├── Record.cs # DNS record entity
│ ├── AzureDnsService.cs # Azure DNS operations
│ ├── DnsRecordActivationService.cs # Background service
│ ├── Dockerfile # Container image
│ ├── appsettings.json # Configuration
│ └── backend.csproj # Project file
├── frontend/
│ ├── src/
│ │ ├── App.jsx # Router + auth state
│ │ ├── config.js # App configuration
│ │ ├── utils/
│ │ │ └── api.js # Auth header helpers
│ │ ├── components/
│ │ │ ├── SignupForm.jsx
│ │ │ ├── LoginForm.jsx
│ │ │ └── ManagementPage.jsx # DNS record table
│ │ └── pages/
│ │ ├── AddDnsRecordPage.jsx
│ │ └── EditDnsRecordPage.jsx
│ ├── public/
│ │ └── favicon.svg
│ └── index.html
├── infrastructure/
│ ├── kubernetes-deployment.yaml # K8s manifests
│ └── README.md # Deployment guide
├── .github/
│ └── copilot-instructions.md # AI agent instructions
└── README.md
- Sign Up: Create account and save your token
- Login: Authenticate with email + token
- Add DNS Record: Create hostname with IP address (status:
added) - Wait 5 Minutes: Background service creates record in Azure DNS (status:
active) - Update Record: Change IP or hostname (status:
updated) - Auto-Expire: Records not updated within TTL marked
inactive - Delete Record: Mark as
inactive, removed from Azure DNS on next cycle
Id(int, PK)UserEmail(string)Token(GUID)
Id(int, PK)Token(string, FK to User)IpAddress(string)Hostname(string, unique globally)OldHostname(string?, nullable)Status(string: added/active/refreshed/inactive)LastUpdatedAt(DateTime)
This project is licensed under the MIT License.