Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -260,9 +260,9 @@ helm-package: set-helm-overlay generate release-manifests helm
install-mockgen:
go install github.com/golang/mock/mockgen@v1.6.0
mockgen: install-mockgen
mockgen -source=./common/flagdinjector/flagdinjector.go -destination=./common/flagdinjector/mock/flagd-injector.go -package=commonmock
mockgen -source=./controllers/core/flagd/controller.go -destination=controllers/core/flagd/mock/mock.go -package=commonmock
mockgen -source=./controllers/core/flagd/resources/interface.go -destination=controllers/core/flagd/resources/mock/mock.go -package=commonmock
mockgen -source=./internal/common/flagdinjector/flagdinjector.go -destination=./internal/common/flagdinjector/mock/flagd-injector.go -package=commonmock
mockgen -source=./internal/controller/core/flagd/controller.go -destination=./internal/controller/core/flagd/mock/mock.go -package=commonmock
mockgen -source=./internal/controller/core/flagd/resources/interface.go -destination=./internal/controller/core/flagd/resources/mock/mock.go -package=commonmock

workspace-init: workspace-clean
go work init
Expand Down
5 changes: 5 additions & 0 deletions api/core/v1beta1/common/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ const (
SyncProviderFilepath SyncProviderType = "file"
SyncProviderAzureBlob SyncProviderType = "azblob"
SyncProviderGcs SyncProviderType = "gcs"
SyncProviderS3 SyncProviderType = "s3"
SyncProviderHttp SyncProviderType = "http"
SyncProviderGrpc SyncProviderType = "grpc"
SyncProviderFlagdProxy SyncProviderType = "flagd-proxy"
Expand Down Expand Up @@ -68,6 +69,10 @@ func (s SyncProviderType) IsGcs() bool {
return s == SyncProviderGcs
}

func (s SyncProviderType) IsS3() bool {
return s == SyncProviderS3
}

func (s SyncProviderType) IsFilepath() bool {
return s == SyncProviderFilepath
}
Expand Down
4 changes: 4 additions & 0 deletions api/core/v1beta1/common/common_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,20 +14,24 @@ func Test_FeatureFlagSource_SyncProvider(t *testing.T) {
g := SyncProviderGrpc
gcs := SyncProviderGcs
azureBlob := SyncProviderAzureBlob
s3 := SyncProviderS3

require.True(t, k.IsKubernetes())
require.True(t, f.IsFilepath())
require.True(t, h.IsHttp())
require.True(t, g.IsGrpc())
require.True(t, gcs.IsGcs())
require.True(t, azureBlob.IsAzureBlob())
require.True(t, s3.IsS3())

require.False(t, f.IsKubernetes())
require.False(t, h.IsFilepath())
require.False(t, k.IsGrpc())
require.False(t, g.IsHttp())
require.False(t, g.IsGcs())
require.False(t, gcs.IsAzureBlob())
require.False(t, s3.IsGcs())
require.False(t, azureBlob.IsS3())
}

func Test_FLagSourceConfiguration_EnvVarKey(t *testing.T) {
Expand Down
9 changes: 7 additions & 2 deletions api/core/v1beta1/featureflagsource_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ type Source struct {
// Source is a URI of the flag sources
Source string `json:"source"`

// Provider type - kubernetes, http(s), grpc(s) or file
// Provider type - kubernetes, file, http(s), grpc(s), gcs, azblob, s3 or flagd-proxy
// +optional
Provider common.SyncProviderType `json:"provider"`

Expand Down Expand Up @@ -266,7 +266,12 @@ func (fc *FeatureFlagSourceSpec) Merge(new *FeatureFlagSourceSpec) {
}

func (fc *FeatureFlagSourceSpec) decorateEnvVarName(original string) string {
if strings.HasPrefix(original, "AZURE_STORAGE") {
// credential env vars for cloud blob sync providers must reach the sidecar
// unmodified; flagd/gocloud reads the vendor-native names directly
// (AZURE_STORAGE_* for azblob, AWS_* for s3, GOOGLE_* for gcs)
if strings.HasPrefix(original, "AZURE_STORAGE") ||
strings.HasPrefix(original, "AWS_") ||
strings.HasPrefix(original, "GOOGLE_") {
return original
}
return common.EnvVarKey(fc.EnvVarPrefix, original)
Expand Down
24 changes: 24 additions & 0 deletions api/core/v1beta1/featureflagsource_types_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,18 @@ func Test_FLagSourceConfiguration_ToEnvVars(t *testing.T) {
Name: "AZURE_STORAGE_KEY",
Value: "key456",
},
{
Name: "AWS_ACCESS_KEY_ID",
Value: "AKIAIOSFODNN7EXAMPLE",
},
{
Name: "AWS_REGION",
Value: "us-east-1",
},
{
Name: "GOOGLE_APPLICATION_CREDENTIALS",
Value: "/var/run/secrets/gcp/key.json",
},
},
EnvVarPrefix: "PRE",
ManagementPort: 22,
Expand All @@ -272,6 +284,18 @@ func Test_FLagSourceConfiguration_ToEnvVars(t *testing.T) {
Name: "AZURE_STORAGE_KEY",
Value: "key456",
},
{
Name: "AWS_ACCESS_KEY_ID",
Value: "AKIAIOSFODNN7EXAMPLE",
},
{
Name: "AWS_REGION",
Value: "us-east-1",
},
{
Name: "GOOGLE_APPLICATION_CREDENTIALS",
Value: "/var/run/secrets/gcp/key.json",
},
{
Name: "PRE_MANAGEMENT_PORT",
Value: "22",
Expand Down
2 changes: 1 addition & 1 deletion chart/open-feature-operator/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ The command removes all the Kubernetes components associated with the chart and
| `sidecarConfiguration.image.tag` | Sets the version tag for the injected sidecar. | `v0.15.4` |
| `sidecarConfiguration.providerArgs` | Used to append arguments to the sidecar startup command. This value is a comma separated string of key values separated by '=', e.g. `key=value,key2=value2` results in the appending of `--sync-provider-args key=value --sync-provider-args key2=value2`. | `""` |
| `sidecarConfiguration.envVarPrefix` | Sets the prefix for all environment variables set in the injected sidecar. | `FLAGD` |
| `sidecarConfiguration.defaultSyncProvider` | Sets the value of the `XXX_SYNC_PROVIDER` environment variable for the injected sidecar container. There are 4 valid sync providers: `kubernetes`, `grpc`, `file` and `http`. | `kubernetes` |
| `sidecarConfiguration.defaultSyncProvider` | Sets the value of the `XXX_SYNC_PROVIDER` environment variable for the injected sidecar container. Valid sync providers: `kubernetes`, `file`, `http`, `grpc`, `gcs`, `azblob`, `s3` and `flagd-proxy`. | `kubernetes` |
| `sidecarConfiguration.evaluator` | Sets the value of the `XXX_EVALUATOR` environment variable for the injected sidecar container. | `json` |
| `sidecarConfiguration.logFormat` | Sets the value of the `XXX_LOG_FORMAT` environment variable for the injected sidecar container. There are 2 valid log formats: `json` and `console`. | `json` |
| `sidecarConfiguration.probesEnabled` | Enable or Disable Liveness and Readiness probes of the flagd sidecar. When enabled, HTTP probes( paths - `/readyz`, `/healthz`) are set with an initial delay of 5 seconds. | `true` |
Expand Down
2 changes: 1 addition & 1 deletion chart/open-feature-operator/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ sidecarConfiguration:
providerArgs: ""
## @param sidecarConfiguration.envVarPrefix Sets the prefix for all environment variables set in the injected sidecar.
envVarPrefix: "FLAGD"
## @param sidecarConfiguration.defaultSyncProvider Sets the value of the `XXX_SYNC_PROVIDER` environment variable for the injected sidecar container. There are 4 valid sync providers: `kubernetes`, `grpc`, `file` and `http`.
## @param sidecarConfiguration.defaultSyncProvider Sets the value of the `XXX_SYNC_PROVIDER` environment variable for the injected sidecar container. Valid sync providers: `kubernetes`, `file`, `http`, `grpc`, `gcs`, `azblob`, `s3` and `flagd-proxy`.
defaultSyncProvider: kubernetes
## @param sidecarConfiguration.evaluator Sets the value of the `XXX_EVALUATOR` environment variable for the injected sidecar container.
evaluator: json
Expand Down
66 changes: 66 additions & 0 deletions common/flagdinjector/mock/flagd-injector.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions config/crd/bases/core.openfeature.dev_featureflagsources.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -312,8 +312,8 @@ spec:
format: int32
type: integer
provider:
description: Provider type - kubernetes, http(s), grpc(s) or
file
description: Provider type - kubernetes, file, http(s), grpc(s),
gcs, azblob, s3 or flagd-proxy
type: string
providerID:
description: ProviderID is an identifier to be used in grpc
Expand Down
2 changes: 1 addition & 1 deletion docs/crds.md
Original file line number Diff line number Diff line change
Expand Up @@ -473,7 +473,7 @@ detected in this CR, defaults to false<br/>
<td><b>provider</b></td>
<td>string</td>
<td>
Provider type - kubernetes, http(s), grpc(s) or file<br/>
Provider type - kubernetes, file, http(s), grpc(s), gcs, azblob, s3 or flagd-proxy<br/>
</td>
<td>false</td>
</tr><tr>
Expand Down
84 changes: 77 additions & 7 deletions docs/feature_flag_source.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,21 +83,91 @@ sources:
selector: 'source=database,app=weatherapp' # flag filtering options
```

### Azure Blob Storage
### Cloud blob storage providers

The `azblob`, `gcs`, and `s3` providers use [Go CDK](https://gocloud.dev/howto/blob/)
to access cloud object storage. Because the underlying SDKs expect their
native credential env vars (e.g. `AWS_ACCESS_KEY_ID`,
`GOOGLE_APPLICATION_CREDENTIALS`, `AZURE_STORAGE_ACCOUNT`), the operator
forwards env vars matching the following prefixes to the flagd sidecar
**without** applying the configured `envVarPrefix`:

| Provider | Passthrough prefix |
|----------|--------------------|
| `azblob` | `AZURE_STORAGE_*` |
| `gcs` | `GOOGLE_*` |
| `s3` | `AWS_*` |

All other env vars are prefixed as usual (e.g. `FLAGD_MY_VAR`).

#### Azure Blob Storage

Given below is an example configuration with provider type `azblob` and supported options,

```yaml
sources:
- source: azblob://my-bucket/test.json # my-bucket - container name
provider: azblob
envVars:
- name: AZURE_STORAGE_ACCOUNT
value: <account_name>
- name: AZURE_STORAGE_SAS_TOKEN
value: <SAS token>
envVars:
- name: AZURE_STORAGE_ACCOUNT
value: <account_name>
- name: AZURE_STORAGE_SAS_TOKEN
value: <SAS token>
```

Other types of credentials for Azure Blob Storage are supported; for details see
[AZ credentials config](https://pkg.go.dev/gocloud.dev/blob/azureblob#hdr-URLs).

#### Google Cloud Storage

Given below is an example configuration with provider type `gcs` and supported options,

```yaml
sources:
- source: gs://my-bucket/flags.json # my-bucket - GCS bucket name
provider: gcs
interval: 10 # optional polling interval in seconds, defaults to 5
envVars:
- name: GOOGLE_APPLICATION_CREDENTIALS
value: /var/run/secrets/gcp/key.json
```

On GKE, prefer [Workload Identity](https://cloud.google.com/kubernetes-engine/docs/how-to/workload-identity)
over static credentials. For the full set of supported URL options see
the [gocloud `blob/gcsblob` URL reference](https://pkg.go.dev/gocloud.dev/blob/gcsblob#hdr-URLs).

#### Amazon S3

Given below is an example configuration with provider type `s3` and supported options,

```yaml
sources:
- source: s3://my-bucket/flags.json # my-bucket - S3 bucket name
provider: s3
interval: 10 # optional polling interval in seconds, defaults to 5
envVars:
- name: AWS_REGION
value: us-east-1
- name: AWS_ACCESS_KEY_ID
valueFrom:
secretKeyRef:
name: s3-credentials
key: access-key-id
- name: AWS_SECRET_ACCESS_KEY
valueFrom:
secretKeyRef:
name: s3-credentials
key: secret-access-key
```
Other type of credentials for Azure Blob Storage are supported, for details (see [AZ credentials config](https://pkg.go.dev/gocloud.dev/blob/azureblob#hdr-URLs))

On EKS, prefer [IRSA](https://docs.aws.amazon.com/eks/latest/userguide/iam-roles-for-service-accounts.html)
or EKS Pod Identity over static access keys; both auto-inject the right
`AWS_*` variables via the pod's service account.

For S3-compatible endpoints such as MinIO or LocalStack, set
`AWS_ENDPOINT_URL_S3` and (usually) `AWS_S3_FORCE_PATH_STYLE=true`, or pass
URL query parameters directly on the source URI. See the [gocloud `blob/s3blob` URL reference](https://pkg.go.dev/gocloud.dev/blob/s3blob#hdr-URLs)
for the full set of supported URL options.

## Sidecar configurations

Expand Down
10 changes: 10 additions & 0 deletions internal/common/flagdinjector/flagdinjector.go
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,8 @@ func (fi *FlagdContainerInjector) newSourceConfig(ctx context.Context, source ap
sourceCfg, err = fi.toFlagdProxyConfig(ctx, objectMeta, source)
case source.Provider.IsAzureBlob():
sourceCfg = fi.toAzureBlobConfig(source)
case source.Provider.IsS3():
sourceCfg = fi.toS3Config(source)
default:
err = fmt.Errorf("could not add provider %s: %w", source.Provider, common.ErrUnrecognizedSyncProvider)
}
Expand Down Expand Up @@ -360,6 +362,14 @@ func (fi *FlagdContainerInjector) toAzureBlobConfig(source api.Source) types.Sou
}
}

func (fi *FlagdContainerInjector) toS3Config(source api.Source) types.SourceConfig {
return types.SourceConfig{
URI: source.Source,
Provider: string(apicommon.SyncProviderS3),
Interval: source.Interval,
}
}

func (fi *FlagdContainerInjector) toFlagdProxyConfig(ctx context.Context, objectMeta *metav1.ObjectMeta, source api.Source) (types.SourceConfig, error) {
// does the proxy exist
exists, ready, err := fi.isFlagdProxyReady(ctx)
Expand Down
Loading
Loading