# cloud_config_service

A lightweight, unified configuration loader for local development, AWS, Azure, and GCP. It centralizes your environment variables in one place (Parameter Store / App Configuration / Secret Manager) and loads them into `os.environ` at runtime. Also provides a simple decorator to ensure config is loaded before your handler executes.

## Features

- Local: Loads from `.env`
- AWS: Loads from SSM Parameter Store (GetParametersByPath)
- Azure: Loads from Azure App Configuration (connection string or endpoint + Managed Identity)
- GCP: Loads from Secret Manager (lists all secrets in a project and reads latest version)
- Single `load_cloud_config()` entrypoint and `with_cloud_config()` decorator
- Cross-platform (Windows, macOS, Linux)
- Minimal imports: cloud SDKs are only imported when needed

## Installation

```bash
pip install cloud_config_service
```

Or from source in your repository root (where README.md and setup.py live):

```bash
pip install .
```

## Quick Start

Set two environment variables:
- `CLOUD_PROVIDER`: one of `local`, `aws`, `azure`, `gcp`
- `CONFIG_LOCATION`: path/endpoint for the provider (see Providers below). For `local`, you can leave it empty.

Then:

```python
from cloud_config_service.config_loader import load_cloud_config

config = load_cloud_config()
# Values are now available via os.environ
```

## Providers

### Local
- `CLOUD_PROVIDER=local`
- `.env` in your current working directory is loaded (key=value pairs).
- Example `.env`:
  ```
  DATABASE_URL=postgresql://localhost:5432/mydb
  API_KEY=your-api-key
  JWT_SECRET=supersecret
  ENVIRONMENT=development
  ```

### AWS (SSM Parameter Store)
- `CLOUD_PROVIDER=aws`
- `CONFIG_LOCATION=/trident/awsmarketplace/dev` (path prefix)
- Permissions: IAM role needs `ssm:GetParametersByPath`.
- SDK: `boto3`

### Azure (App Configuration)
- `CLOUD_PROVIDER=azure`
- `CONFIG_LOCATION=` either:
  - Connection string: `Endpoint=https://your-app-config.azconfig.io;Id=...;Secret=...`
  - Endpoint URL: `https://your-app-config.azconfig.io` (uses Managed Identity via `DefaultAzureCredential`)
- SDKs: `azure-appconfiguration`, `azure-identity`

### GCP (Secret Manager)
- `CLOUD_PROVIDER=gcp`
- `CONFIG_LOCATION=projects/YOUR_PROJECT_ID`
- Auth: ADC (Application Default Credentials) or service account with Secret Manager access.
- SDK: `google-cloud-secret-manager`

## Usage

### 1) Explicit load

```python
import os
from cloud_config_service.config_loader import load_cloud_config

# Typically set in your environment/platform:
# os.environ["CLOUD_PROVIDER"] = "aws"
# os.environ["CONFIG_LOCATION"] = "/trident/awsmarketplace/dev"

config = load_cloud_config()  # returns dict and sets environment variables

print("DATABASE_URL:", os.getenv("DATABASE_URL"))
print("API_KEY:", os.getenv("API_KEY"))
```

### 2) Decorator for handlers

Use `with_cloud_config()` to ensure config is loaded before your function runs. Good for AWS Lambda/Azure Functions.

```python
import os
from cloud_config_service.config_loader import with_cloud_config

@with_cloud_config()
def lambda_handler(event, context):
    token = os.getenv("JWT_SECRET")
    return {"statusCode": 200, "body": "OK"}
```

### Stacking with other decorators (e.g., JWT)

```python
import functools
import os
from cloud_config_service.config_loader import with_cloud_config

def jwt_middleware(func):
    @functools.wraps(func)
    def wrapper(event, context):
        jwt_secret = os.getenv("JWT_SECRET")
        # validate token using jwt_secret
        return func(event, context)
    return wrapper

@with_cloud_config()  # load config first
@jwt_middleware
def lambda_handler(event, context):
    return {"statusCode": 200, "body": "OK"}
```

## Environment Variables Reference

- `CLOUD_PROVIDER`:
  - `local` | `aws` | `azure` | `gcp`
  - Default: `local`.

- `CONFIG_LOCATION`:
  - local: optional (loads `.env` from current working directory)
  - aws: required (e.g., `/my/app/dev`)
  - azure: required (connection string `Endpoint=...;Id=...;Secret=...` or endpoint URL)
  - gcp: required (e.g., `projects/my-project`)

## Permissions and Auth

- AWS: Lambda/EC2 role needs `ssm:GetParametersByPath`.
- Azure: If using endpoint URL, assign Managed Identity to allow App Configuration access. If using connection string, MSI not required.
- GCP: Ensure your service account or ADC has Secret Manager access and `roles/secretmanager.secretAccessor`.

## Error Handling

- Missing SDKs are handled gracefully with guidance to install them:
  - `boto3` for AWS
  - `azure-appconfiguration` and `azure-identity` for Azure
  - `google-cloud-secret-manager` for GCP
  - `python-dotenv` for local `.env`
- Provider exceptions are caught and printed; wrap `load_cloud_config()` in your own error handling for production if desired.

## API

```python
from cloud_config_service import load_cloud_config, with_cloud_config
```

- `load_cloud_config() -> Dict[str, str]`:
  - Reads envs, loads config from the selected provider, returns a dict, and sets `os.environ`.

- `with_cloud_config()`:
  - Decorator that calls `load_cloud_config()` before the wrapped function executes.

## Development

- Python >= 3.8 recommended.
- To run locally with `.env`, set `CLOUD_PROVIDER=local` and ensure a `.env` exists in your working directory.

## License

MIT
