|
| 1 | +# GCP Provider |
| 2 | + |
| 3 | +An OpenFeature provider that reads feature flags from Google Cloud. Currently supports [Google Cloud Secret Manager](https://cloud.google.com/secret-manager), purpose-built for secrets requiring versioning, rotation, and fine-grained IAM access control. |
| 4 | + |
| 5 | +## Installation |
| 6 | + |
| 7 | +<!-- x-release-please-start-version --> |
| 8 | +```xml |
| 9 | +<dependency> |
| 10 | + <groupId>dev.openfeature.contrib.providers</groupId> |
| 11 | + <artifactId>gcp</artifactId> |
| 12 | + <version>0.0.1</version> |
| 13 | +</dependency> |
| 14 | +``` |
| 15 | +<!-- x-release-please-end-version --> |
| 16 | + |
| 17 | +## Quick Start |
| 18 | + |
| 19 | +```java |
| 20 | +import dev.openfeature.contrib.providers.gcp.GcpSecretManagerProvider; |
| 21 | +import dev.openfeature.contrib.providers.gcp.GcpSecretManagerProviderOptions; |
| 22 | +import dev.openfeature.sdk.OpenFeatureAPI; |
| 23 | + |
| 24 | +GcpProviderOptions options = GcpSecretManagerProviderOptions.builder() |
| 25 | + .projectId("my-gcp-project") |
| 26 | + .build(); |
| 27 | + |
| 28 | +OpenFeatureAPI.getInstance().setProvider(new GcpSecretManagerProvider(options)); |
| 29 | + |
| 30 | +// Evaluate a boolean flag stored as secret "enable-dark-mode" with value "true" |
| 31 | +boolean darkMode = OpenFeatureAPI.getInstance().getClient() |
| 32 | + .getBooleanValue("enable-dark-mode", false); |
| 33 | +``` |
| 34 | + |
| 35 | +## How It Works |
| 36 | + |
| 37 | +Each feature flag is stored as an individual **secret** in GCP Secret Manager. The flag key maps directly to the secret name (with an optional prefix). The `latest` version is accessed by default. |
| 38 | + |
| 39 | +Supported raw value formats: |
| 40 | + |
| 41 | +| Flag type | Secret value example | |
| 42 | +|-----------|---------------------| |
| 43 | +| Boolean | `true` or `false` | |
| 44 | +| Integer | `42` | |
| 45 | +| Double | `3.14` | |
| 46 | +| String | `dark-mode` | |
| 47 | +| Object | `{"color":"blue","level":3}` | |
| 48 | + |
| 49 | +## Authentication |
| 50 | + |
| 51 | +The provider uses [Application Default Credentials (ADC)](https://cloud.google.com/docs/authentication/provide-credentials-adc) by default. No explicit credentials are required when running on GCP infrastructure (Cloud Run, GKE, Compute Engine) or when `gcloud auth application-default login` has been run locally. |
| 52 | + |
| 53 | +To use explicit credentials: |
| 54 | + |
| 55 | +```java |
| 56 | +import com.google.auth.oauth2.ServiceAccountCredentials; |
| 57 | +import java.io.FileInputStream; |
| 58 | + |
| 59 | +GoogleCredentials credentials = ServiceAccountCredentials.fromStream( |
| 60 | + new FileInputStream("/path/to/service-account-key.json")); |
| 61 | + |
| 62 | +GcpSecretManagerProviderOptions options = GcpSecretManagerProviderOptions.builder() |
| 63 | + .projectId("my-gcp-project") |
| 64 | + .credentials(credentials) |
| 65 | + .build(); |
| 66 | +``` |
| 67 | + |
| 68 | +## Configuration Options |
| 69 | + |
| 70 | +| Option | Type | Default | Description | |
| 71 | +|--------|------|---------|-------------| |
| 72 | +| `projectId` | `String` | *(required)* | GCP project ID that owns the secrets | |
| 73 | +| `credentials` | `GoogleCredentials` | `null` (ADC) | Explicit credentials; falls back to Application Default Credentials when null | |
| 74 | +| `version` | `String` | `"latest"` | Secret version to access. Use `"latest"` for the current version or a numeric string (e.g. `"3"`) to pin to a specific version | |
| 75 | +| `cacheExpiry` | `Duration` | `5 minutes` | How long fetched secret values are cached before re-fetching from GCP | |
| 76 | +| `cacheMaxSize` | `int` | `500` | Maximum number of secret values held in the in-memory cache | |
| 77 | +| `namePrefix` | `String` | `null` | Optional prefix prepended to every flag key. E.g. prefix `"ff-"` maps flag `"my-flag"` to secret `"ff-my-flag"` | |
| 78 | + |
| 79 | +## Advanced Usage |
| 80 | + |
| 81 | +### Pinning to a specific secret version |
| 82 | + |
| 83 | +```java |
| 84 | +GcpSecretManagerProviderOptions options = GcpSecretManagerProviderOptions.builder() |
| 85 | + .projectId("my-gcp-project") |
| 86 | + .secretVersion("5") // always use version 5 |
| 87 | + .build(); |
| 88 | +``` |
| 89 | + |
| 90 | +### Secret name prefix |
| 91 | + |
| 92 | +```java |
| 93 | +GcpSecretManagerProviderOptions options = GcpSecretManagerProviderOptions.builder() |
| 94 | + .projectId("my-gcp-project") |
| 95 | + .namePrefix("feature-flags/") |
| 96 | + .build(); |
| 97 | +``` |
| 98 | + |
| 99 | +### Tuning cache for high-throughput scenarios |
| 100 | + |
| 101 | +Secret Manager has API quotas (10,000 access operations per minute per project). Use a longer `cacheExpiry` to stay within quota. |
| 102 | + |
| 103 | +```java |
| 104 | +GcpSecretManagerProviderOptions options = GcpSecretManagerProviderOptions.builder() |
| 105 | + .projectId("my-gcp-project") |
| 106 | + .cacheExpiry(Duration.ofMinutes(10)) |
| 107 | + .cacheMaxSize(1000) |
| 108 | + .build(); |
| 109 | +``` |
| 110 | + |
| 111 | +## Running Integration Tests |
| 112 | + |
| 113 | +Integration tests require real GCP credentials and pre-created test secrets. |
| 114 | + |
| 115 | +1. Configure ADC: `gcloud auth application-default login` |
| 116 | +2. Create test secrets in your project (see `GcpSecretManagerProviderIntegrationTest` for the required secret names and values) |
| 117 | +3. Run: |
| 118 | + |
| 119 | +```bash |
| 120 | +GCP_PROJECT_ID=my-project mvn verify -pl providers/gcp -Dgroups=integration |
| 121 | +``` |
0 commit comments