Documentation
¶
Overview ¶
Package env provides environment variable utilities for Azure Developer CLI (azd) extensions.
This package includes:
- Key Vault reference resolution (ResolveMap, ResolveSlice)
- Format conversion (MapToSlice, SliceToMap)
- Pattern-based extraction (FilterByPrefix, ExtractPattern)
- Service name normalization (NormalizeServiceName)
Key Vault Resolution ¶
Use ResolveMap to resolve Azure Key Vault references in environment maps:
import (
"github.com/jongio/azd-core/env"
"github.com/jongio/azd-core/keyvault"
)
resolver, err := keyvault.NewKeyVaultResolver()
if err != nil {
return err
}
envMap := map[string]string{
"DATABASE_URL": "postgres://localhost/db",
"API_KEY": "@Microsoft.KeyVault(VaultName=myvault;SecretName=api-key)",
}
resolved, warnings, err := env.ResolveMap(ctx, envMap, resolver, keyvault.ResolveEnvironmentOptions{})
if err != nil {
return err
}
// resolved["API_KEY"] now contains the actual secret value from Key Vault
Pattern-Based Extraction ¶
Extract environment variables matching specific patterns:
// Filter by prefix (case-insensitive)
azureVars := env.FilterByPrefix(envVars, "AZURE_")
// Returns: {"AZURE_TENANT_ID": "xyz", "AZURE_CLIENT_ID": "abc"}
// Extract SERVICE_*_URL with normalization
serviceURLs := env.ExtractPattern(envVars, env.PatternOptions{
Prefix: "SERVICE_",
Suffix: "_URL",
TrimPrefix: true,
TrimSuffix: true,
Transform: env.NormalizeServiceName,
})
// Returns: {"my-api": "https://...", "web-app": "https://..."}
Service Name Normalization ¶
Convert environment variable naming to service naming conventions:
serviceName := env.NormalizeServiceName("MY_API_SERVICE")
// Returns: "my-api-service"
This is useful for converting uppercase underscore-separated names (common in environment variables) to lowercase hyphen-separated names (common in service identifiers, DNS labels, and container names).
Supported Key Vault Reference Formats ¶
- @Microsoft.KeyVault(SecretUri=https://...)
- @Microsoft.KeyVault(VaultName=...;SecretName=...;SecretVersion=...)
- akvs://<subscription-id>/<vault-name>/<secret-name>[/<version>]
Authentication ¶
Key Vault resolution uses azidentity.DefaultAzureCredential, which supports:
- Environment variables (AZURE_TENANT_ID, AZURE_CLIENT_ID, AZURE_CLIENT_SECRET)
- Managed identity (Azure VM, App Service, Container Apps)
- Azure CLI (az login)
- Azure PowerShell
- Interactive browser authentication
Error Handling ¶
By default, resolution continues even if individual references fail (warnings are collected). Use StopOnError to fail fast:
opts := keyvault.ResolveEnvironmentOptions{StopOnError: true}
resolved, warnings, err := env.ResolveMap(ctx, envMap, resolver, opts)
if err != nil {
// First error encountered
}
Package env provides environment variable resolution utilities with Azure Key Vault integration.
This package makes it easy for consumers (like azd-app and azd-exec) to resolve Azure Key Vault references in environment variables. It provides adapter functions to work with both map[string]string and []string representations of environment variables.
Usage with Environment Maps ¶
Use ResolveMap when working with environment maps:
resolver, err := keyvault.NewKeyVaultResolver()
if err != nil {
// handle error
}
envMap := map[string]string{
"DATABASE_URL": "postgres://localhost/db",
"API_KEY": "@Microsoft.KeyVault(VaultName=myvault;SecretName=api-key)",
}
resolved, warnings, err := env.ResolveMap(ctx, envMap, resolver, keyvault.ResolveEnvironmentOptions{})
if err != nil {
// handle error
}
for _, w := range warnings {
// log warning: w.Key, w.Err
}
// resolved["API_KEY"] now contains the actual secret value from Key Vault
Usage with Environment Slices ¶
Use ResolveSlice when working with KEY=VALUE slices (e.g., from os.Environ()):
resolver, err := keyvault.NewKeyVaultResolver()
if err != nil {
// handle error
}
envSlice := os.Environ() // or []string{"KEY=value", ...}
resolved, warnings, err := env.ResolveSlice(ctx, envSlice, resolver, keyvault.ResolveEnvironmentOptions{})
if err != nil {
// handle error
}
// Use resolved with exec.Cmd: cmd.Env = resolved
Error Handling Options ¶
By default, resolution continues even if individual references fail (warnings are collected). Use StopOnError to fail fast:
opts := keyvault.ResolveEnvironmentOptions{StopOnError: true}
resolved, warnings, err := env.ResolveMap(ctx, envMap, resolver, opts)
if err != nil {
// Resolution failed, warnings contains details
}
Supported Key Vault Reference Formats ¶
The package supports three Key Vault reference formats:
- @Microsoft.KeyVault(SecretUri=https://vault.vault.azure.net/secrets/name/version)
- @Microsoft.KeyVault(VaultName=vault;SecretName=name;SecretVersion=version)
- akvs://guid/vault/secret/version
Helper Functions ¶
The package also provides utility functions for working with environment variables:
- MapToSlice: Convert map[string]string to []string (KEY=VALUE format)
- SliceToMap: Convert []string to map[string]string (skips malformed entries)
- HasKeyVaultReferences: Check if any Key Vault references exist
Index ¶
- func ExtractPattern(envVars map[string]string, opts PatternOptions) map[string]string
- func FilterByPrefix(envVars map[string]string, prefix string) map[string]string
- func FilterByPrefixSlice(envSlice []string, prefix string) []string
- func GetAzdEnvironmentValues(ctx context.Context, envName string) (map[string]string, error)
- func HasKeyVaultReferences(envVars []string) bool
- func LoadAzdEnvironment(ctx context.Context, envName string) error
- func MapToSlice(env map[string]string) []string
- func NormalizeServiceName(envVarName string) string
- func ParseKeyValueFormat(output []byte) (map[string]string, error)
- func Resolve(ctx context.Context, env map[string]string, resolver Resolver, ...) (map[string]string, []keyvault.KeyVaultResolutionWarning, error)
- func ResolveMap(ctx context.Context, envMap map[string]string, resolver Resolver, ...) (map[string]string, []keyvault.KeyVaultResolutionWarning, error)
- func ResolveSlice(ctx context.Context, envSlice []string, resolver Resolver, ...) ([]string, []keyvault.KeyVaultResolutionWarning, error)
- func SliceToMap(envSlice []string) map[string]string
- type CommandRunner
- type DefaultCommandRunner
- type PatternOptions
- type Resolver
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func ExtractPattern ¶ added in v0.3.0
func ExtractPattern(envVars map[string]string, opts PatternOptions) map[string]string
ExtractPattern extracts environment variables matching prefix/suffix with key transformation. Pattern matching is case-insensitive. Returns a new map with transformed keys.
Example:
envVars := map[string]string{
"SERVICE_API_URL": "https://api.example.com",
"SERVICE_WEB_URL": "https://web.example.com",
"SERVICE_DB_HOST": "db.example.com",
}
// Extract all SERVICE_*_URL variables and normalize service names
urls := env.ExtractPattern(envVars, env.PatternOptions{
Prefix: "SERVICE_",
Suffix: "_URL",
TrimPrefix: true,
TrimSuffix: true,
Transform: func(s string) string { return strings.ToLower(strings.ReplaceAll(s, "_", "-")) },
})
// Returns: {"api": "https://api.example.com", "web": "https://web.example.com"}
func FilterByPrefix ¶ added in v0.3.0
FilterByPrefix returns environment variables matching a prefix. The prefix matching is case-insensitive for keys. Returns a new map containing only the matching entries.
Example:
envVars := map[string]string{
"AZURE_TENANT_ID": "xyz",
"AZURE_CLIENT_ID": "abc",
"DATABASE_URL": "postgres://...",
}
azureVars := env.FilterByPrefix(envVars, "AZURE_")
// Returns: {"AZURE_TENANT_ID": "xyz", "AZURE_CLIENT_ID": "abc"}
func FilterByPrefixSlice ¶ added in v0.3.0
FilterByPrefixSlice returns KEY=VALUE pairs matching a prefix. The prefix matching is case-insensitive for keys. Returns a new slice containing only the matching entries. Malformed entries (without "=") are skipped.
Example:
envSlice := []string{
"AZURE_TENANT_ID=xyz",
"AZURE_CLIENT_ID=abc",
"DATABASE_URL=postgres://...",
}
azureVars := env.FilterByPrefixSlice(envSlice, "AZURE_")
// Returns: ["AZURE_TENANT_ID=xyz", "AZURE_CLIENT_ID=abc"]
func GetAzdEnvironmentValues ¶ added in v0.4.0
GetAzdEnvironmentValues retrieves all environment variables from the specified azd environment without setting them. This is useful when you need the values but don't want to modify the current process environment.
func HasKeyVaultReferences ¶
HasKeyVaultReferences quickly checks for any key vault formatted values.
func LoadAzdEnvironment ¶ added in v0.4.0
LoadAzdEnvironment loads all environment variables from the specified azd environment by calling 'azd env get-values' and sets them in the current process.
This ensures that when the -e flag is used, the correct environment values are loaded.
WORKAROUND: This is a workaround for a limitation in the azd extension framework. Ideally, azd should honor the -e flag before invoking the extension and inject the correct environment variables. However, currently azd injects the default environment from config.json, then passes the -e flag to the extension. This forces us to manually reload the environment using 'azd env get-values'.
func MapToSlice ¶
MapToSlice converts an env map into KEY=VALUE entries.
func NormalizeServiceName ¶ added in v0.3.0
NormalizeServiceName converts environment variable naming to service naming. Converts uppercase underscore-separated names to lowercase hyphen-separated names. Commonly used with ExtractPattern to normalize service names from environment variables.
Example:
name := env.NormalizeServiceName("MY_API_SERVICE")
// Returns: "my-api-service"
name = env.NormalizeServiceName("WEB_APP")
// Returns: "web-app"
func ParseKeyValueFormat ¶ added in v0.4.0
ParseKeyValueFormat parses output in "KEY=value" format (one per line). Handles quoted values and skips empty lines and comments.
func Resolve ¶
func Resolve(ctx context.Context, env map[string]string, resolver Resolver, opts keyvault.ResolveEnvironmentOptions) (map[string]string, []keyvault.KeyVaultResolutionWarning, error)
Resolve applies a key vault resolver to the provided env map if needed.
func ResolveMap ¶
func ResolveMap(ctx context.Context, envMap map[string]string, resolver Resolver, opts keyvault.ResolveEnvironmentOptions) (map[string]string, []keyvault.KeyVaultResolutionWarning, error)
ResolveMap applies the Key Vault resolver to an environment map. It converts the map to a slice, resolves any Key Vault references, and returns a new map with the resolved values. If resolver is nil or no Key Vault references are found, the original map is returned (as a copy).
This is the primary helper for consumers like azd-app and azd-exec that work with environment maps (e.g., from os.Environ() converted to a map).
Example usage:
resolver, err := keyvault.NewKeyVaultResolver()
if err != nil {
// handle error
}
envMap := map[string]string{
"DATABASE_URL": "postgres://localhost/db",
"API_KEY": "@Microsoft.KeyVault(VaultName=myvault;SecretName=api-key)",
}
resolved, warnings, err := env.ResolveMap(ctx, envMap, resolver, keyvault.ResolveEnvironmentOptions{})
if err != nil {
// handle error
}
for _, w := range warnings {
// log warning: w.Key, w.Err
}
// resolved["API_KEY"] now contains the actual secret value
func ResolveSlice ¶
func ResolveSlice(ctx context.Context, envSlice []string, resolver Resolver, opts keyvault.ResolveEnvironmentOptions) ([]string, []keyvault.KeyVaultResolutionWarning, error)
ResolveSlice applies the Key Vault resolver to an environment slice. It takes KEY=VALUE entries, resolves any Key Vault references, and returns a new slice with the resolved values. If resolver is nil or no Key Vault references are found, the original slice is returned (as a copy).
This is useful for consumers that work directly with environment slices (e.g., from os.Environ() or for passing to exec.Cmd.Env).
Example usage:
resolver, err := keyvault.NewKeyVaultResolver()
if err != nil {
// handle error
}
envSlice := []string{
"DATABASE_URL=postgres://localhost/db",
"API_KEY=@Microsoft.KeyVault(VaultName=myvault;SecretName=api-key)",
}
resolved, warnings, err := env.ResolveSlice(ctx, envSlice, resolver, keyvault.ResolveEnvironmentOptions{})
if err != nil {
// handle error
}
for _, w := range warnings {
// log warning: w.Key, w.Err
}
// resolved can now be used with cmd.Env = resolved
func SliceToMap ¶
SliceToMap converts KEY=VALUE entries into a map, skipping malformed rows.
Types ¶
type CommandRunner ¶ added in v0.4.0
type CommandRunner interface {
Run(ctx context.Context, name string, args ...string) ([]byte, error)
}
CommandRunner is an interface for running external commands. This allows for mocking in tests.
func SetCommandRunner ¶ added in v0.4.0
func SetCommandRunner(runner CommandRunner) CommandRunner
SetCommandRunner sets a custom command runner (useful for testing). Returns the previous runner so it can be restored.
type DefaultCommandRunner ¶ added in v0.4.0
type DefaultCommandRunner struct{}
DefaultCommandRunner uses os/exec to run commands.
type PatternOptions ¶ added in v0.3.0
type PatternOptions struct {
// Prefix is the required prefix for keys (e.g., "SERVICE_")
Prefix string
// Suffix is the optional suffix for keys (e.g., "_URL")
Suffix string
// TrimPrefix removes the prefix from result keys if true
TrimPrefix bool
// TrimSuffix removes the suffix from result keys if true
TrimSuffix bool
// Transform is an optional key transformation function applied after trimming
// Example: func(s string) string { return strings.ToLower(s) }
Transform func(string) string
// Validator is an optional value validation function
// If provided, only entries where Validator(value) returns true are included
// Example: func(v string) bool { return v != "" }
Validator func(string) bool
}
PatternOptions configures pattern-based environment variable extraction.