# Settings and Secrets

This guide explains how to manage application settings and secrets in the Developer Platform.

## 📋 Overview

The platform uses a two-tier approach for configuration management:

- **Settings**: Non-sensitive configuration values stored in `settings.yml` and deployed to Azure App Configuration ⚙️
- **Secrets**: Sensitive values stored in Azure DevOps Libraries and deployed to Azure Key Vault 🔐

[TOC]

## ⚙️ Settings Management

### 📁Settings File Structure

Settings are defined in a `settings.yml` file located in the `infra/api/` folder of each project. The file uses a structured format that supports environment-specific overrides.

#### File Location

```
<project-root>/
├── infra/
│   └── app/
│       └── settings.yml
```

#### Settings File Format

```yaml
# This is the settings.yml file used for configuration settings in the application.
# The settings are defined as a list of dictionaries, where each dictionary represents a setting.

# Example of a setting:
# - name: setting1          # The name of the setting
#   value: defaultvalue      # The default value of the setting
#   overrides:              # Optional overrides for specific environments
#     - env: test           # The environment where the override applies
#       value: testvalue    # The value of the setting for the specified environment

# Overrides allow you to specify different values for settings based on the environment.
# For example, you might have a default value for a setting that applies to all environments,
# but you can override this value for specific environments like 'test', 'qa', 'uat', or 'prod'.
# This is useful for managing environment-specific configurations without duplicating the entire settings structure.

- name: DatabaseConnectionTimeout
  value: '30'
  overrides:
    - env: test
      value: '10'
    - env: prod
      value: '60'

- name: ApiBaseUrl
  value: 'https://api.dev.example.com'
  overrides:
    - env: test
      value: 'https://api.test.example.com'
    - env: qa
      value: 'https://api.qa.example.com'
    - env: uat
      value: 'https://api.uat.example.com'
    - env: prod
      value: 'https://api.prod.example.com'

- name: LogLevel
  value: 'Debug'
  overrides:
    - env: prod
      value: 'Information'
```

#### Environment-Specific Overrides

The override system allows you to:

- Define a **default value** that applies to all environments
- Override specific values for targeted environments (`test`, `qa`, `uat`, `prod`)
- Avoid duplicating configuration across environments

### 🚀 Settings Deployment Process

1. **Development**: Define settings in `settings.yml` in your project
2. **Pipeline Processing**: The deployment pipeline reads the settings file
3. **Environment Resolution**: The pipeline applies environment-specific overrides
4. **Azure App Configuration**: Final settings are pushed to Azure App Configuration
5. **Application Access**: Applications retrieve settings from App Configuration

## 🔐 Secrets Management

### 📚 Azure DevOps Library Setup

Secrets are managed through Azure DevOps Variable Groups (Libraries) with the following structure:

#### Library Naming Convention

- **Library Name**: It is recommended to set the library name to match the **Project ID**
- **Example**: If your project ID is `it-api-exp-appname`, the library should be named `it-api-exp-appname`

#### Pipeline Configuration

To pass the Azure DevOps Library to your pipeline templates, add the `secretsVariableGroupName` parameter to **both your main pipeline and PR pipeline**:

```yaml
extends:
  template: azure-dotnet-api-v3.yml@templates
  parameters:
    applicationName: ${{ variables.ApplicationName }}
    projectId: ${{ variables.ProjectId }}
    openAPIFileName: ${{ variables.OpenAPIFileName }}
    dotNetVersion: '10.x'
    secretsVariableGroupName: 'ProjectId1' # 🔑 Azure DevOps Library name
```

**Key Points:**

- The `secretsVariableGroupName` parameter tells the pipeline template which Azure DevOps Library contains your secrets
- **Add this parameter to both pipelines**: Configure it in your main deployment pipeline (`azure-pipelines-api.yml`) and your PR validation pipeline (`azure-pipelines-api-pr.yml`)
- It is recommended that the value matches your Project ID and the variable group name defined in the `variables` section of your pipeline
- Example: If your project ID is `it-api-exp-appname`, use `secretsVariableGroupName: 'it-api-exp-appname'`

#### Secret Naming Convention

```
[ENV]<settingname>
```

Where:

- **ENV**: Environment prefix (`[GLOBAL]`, `[TEST]`, `[QA]`, `[UAT]`, `[PROD]`)
- **settingname**: The name of the secret setting

**Environment Prefix Options:**

- **`[GLOBAL]`**: Applied to all environments by default (can be overridden)
- **`[TEST]`**: Test environment specific
- **`[QA]`**: QA environment specific
- **`[UAT]`**: UAT environment specific
- **`[PROD]`**: Production environment specific

**Override Behavior:**
Environment-specific secrets take precedence over global secrets. For example:

- `[GLOBAL]DatabasePassword` applies to all environments
- `[PROD]DatabasePassword` overrides the global setting for production only
- Other environments (TEST, QA, UAT) continue using the global value

#### Examples

```
# Global secrets (applied to all environments)
[GLOBAL]DatabasePassword
[GLOBAL]ApiKey
[GLOBAL]ServiceUrl

# Environment-specific secrets (override global if present)
[TEST]DatabasePassword      # Overrides global for TEST
[QA]DatabasePassword        # Overrides global for QA
[UAT]DatabasePassword       # Overrides global for UAT
[PROD]DatabasePassword      # Overrides global for PROD

# Mixed example - ApiKey uses global, DatabasePassword has env-specific overrides
[GLOBAL]ApiKey             # Used by all environments
[GLOBAL]DatabasePassword   # Used by QA and UAT
[TEST]DatabasePassword     # Overrides global for TEST
[PROD]DatabasePassword     # Overrides global for PROD
```

### Secret Configuration Requirements

For each secret in the Azure DevOps Library:

1. **Variable Type**: Must be set to `Secret` (not `Variable`)
2. **Environment Prefix**: Use uppercase environment names (`[GLOBAL]`, `[TEST]`, `[QA]`, `[UAT]`, `[PROD]`)
3. **Consistent Naming**: Use the same base name across all environments
4. **Override Hierarchy**: Environment-specific secrets override global secrets for that environment

**Secret Resolution Order:**

1. Check for environment-specific secret (e.g., `[PROD]DatabasePassword`)
2. If not found, use global secret (e.g., `[GLOBAL]DatabasePassword`)
3. If neither exists, the secret is not available

### 🚀 Secrets Deployment Process

1. **Azure DevOps Library**: Define secrets with proper naming convention
2. **Variable Type**: Ensure all secrets are marked as `Secret` type
3. **Pipeline Detection**: Deployment pipeline automatically detects secrets
4. **Key Vault Storage**: Secrets are securely stored in Azure Key Vault
5. **App Configuration Reference**: App Configuration receives references to Key Vault secrets
6. **Application Access**: Applications access secrets through App Configuration with Key Vault integration

## ✨ Best Practices

### ⚙️ Settings Best Practices

- **Use Descriptive Names**: Choose clear, self-explanatory setting names
- **Default Values**: Always provide sensible default values
- **Environment Consistency**: Maintain consistent setting names across environments
- **Documentation**: Comment complex settings in the YAML file
- **Validation**: Test settings in lower environments before production

### 🔐 Secrets Best Practices

- **Minimal Exposure**: Only store truly sensitive data as secrets
- **Rotation**: Regularly rotate secrets, especially API keys and passwords
- **Access Control**: Limit access to Azure DevOps Libraries containing secrets
- **Audit Trail**: Monitor access to secrets in Azure Key Vault
- **Naming Convention**: Strictly follow the `[ENV]<settingname>` format

### 🛡️ Security Considerations

1. **Secrets Never in Code**: Never commit secrets to source control
2. **Environment Separation**: Ensure complete separation between environment secrets
3. **Least Privilege**: Grant minimum necessary permissions for accessing secrets
4. **Regular Review**: Periodically review and cleanup unused secrets
5. **Monitoring**: Enable monitoring and alerting for secret access

## 🔍 Troubleshooting

### ⚠️ Common Issues

#### Settings Not Appearing in App Configuration

- ✅ Verify `settings.yml` exists in `infra/api/` folder
- ✅ Check YAML syntax is valid
- ✅ Ensure pipeline has permissions to App Configuration
- ✅ Confirm environment name matches expected values

#### Secrets Not Accessible

- ✅ Verify Azure DevOps Library name matches what is specified in `secretsVariableGroupName`
- ✅ Check secret naming follows `[ENV]<settingname>` format
- ✅ Ensure variable type is set to `Secret`
- ✅ Confirm pipeline has access to the variable group
- ✅ Verify Key Vault permissions are correctly configured

#### Environment-Specific Values Not Working

- ✅ Check environment name spelling in overrides
- ✅ Verify deployment pipeline is using correct environment parameter
- ✅ Ensure override structure follows the correct YAML format

### 💬 Getting Help

If you encounter issues with settings or secrets configuration:

1. **Check Pipeline Logs**: Review deployment pipeline output for errors
2. **Validate Configuration**: Use YAML validation tools for settings files
3. **Verify Permissions**: Ensure proper access to Azure resources
4. **Contact Platform Team**: Reach out for assistance with complex configurations

## 📂 Example Project Structure

```
AppnameApplication/
├── src/
│   └── [application code]
├── infra/
│   ├── app/
│   │   └── settings.yml          # Application settings
│   └── [infrastructure code]
└── azure-pipelines.yml           # Pipeline configuration
```

Azure DevOps Library: `it-api-exp-appname` (matching project ID)

```
# Global secrets (used by all environments unless overridden)
[GLOBAL]ApiKey = [secret]
[GLOBAL]ServiceUrl = [secret]

# Environment-specific secrets (override global when present)
[TEST]DatabasePassword = [secret]
[QA]DatabasePassword = [secret]
[UAT]DatabasePassword = [secret]
[PROD]DatabasePassword = [secret]

# Mixed example: EmailApiKey uses global for all environments
[GLOBAL]EmailApiKey = [secret]
```

This approach ensures secure, manageable, and environment-appropriate configuration for all applications in the Developer Platform.

## 💻 Using These Settings in Applications

### 🔵 .NET Applications

For detailed information on how to consume these settings in your .NET applications, see the official Microsoft documentation: [Configuration in .NET](https://learn.microsoft.com/en-us/dotnet/core/extensions/configuration)

This guide covers:

- How to read configuration values in your application
- Working with Azure App Configuration provider
- Integrating with dependency injection
- Best practices for configuration management in .NET

---

## 📚 Related Documentation

- [Aspire Config Foundry Example](../../foundry/aspire-config.md) - Working example of publish-time configuration generation with Aspire
