Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
bd5edf3
api: add GCP support for backend security policies and API schemas
sukumargaonkar May 22, 2025
90121fb
Merge remote-tracking branch 'upstream/main' into gcp-auth-api
sukumargaonkar May 22, 2025
6c7df97
api: add GCP auth support in filter configuration
sukumargaonkar May 22, 2025
355ad5a
add validations for fields in BackendSecurityPolicyGCPCredentials
sukumargaonkar May 22, 2025
ebc5147
remove unused dependencies from go.mod
sukumargaonkar May 23, 2025
f541e98
Merge remote-tracking branch 'upstream/main' into gcp-auth-api
sukumargaonkar May 23, 2025
40b1477
Reorganize fields under BackendSecurityPolicyGCPCredentials
sukumargaonkar May 24, 2025
f7e2634
Merge remote-tracking branch 'upstream/main' into gcp-auth-api
sukumargaonkar May 27, 2025
2414542
make precommit
sukumargaonkar May 27, 2025
f7d5192
Add Region and ProjectName to GCPAuth
sukumargaonkar Jun 9, 2025
c538a45
Merge remote-tracking branch 'upstream/main' into gcp-auth-api
sukumargaonkar Jun 9, 2025
e101a82
Rename GCPWorkloadIdentityProvider.OIDCConfig to OIDCProvider
sukumargaonkar Jun 10, 2025
e851bcc
Merge remote-tracking branch 'upstream/main' into gcp-auth-api
sukumargaonkar Jun 10, 2025
7263be3
Fix go.mod
sukumargaonkar Jun 10, 2025
622f5f5
Switch from GCP CredentialFile to AccessToken
sukumargaonkar Jun 11, 2025
3001321
Merge remote-tracking branch 'upstream/main' into gcp-auth-api
sukumargaonkar Jun 11, 2025
c4208b4
Merge remote-tracking branch 'upstream/main' into gcp-auth-api
sukumargaonkar Jun 11, 2025
831b6d2
Fix gitignore
sukumargaonkar Jun 11, 2025
04b7c08
Add crdcel test for gcp backendsecurity policy
sukumargaonkar Jun 11, 2025
2ae31ec
Remove unnecessary comments
sukumargaonkar Jun 12, 2025
fa5d02d
Merge remote-tracking branch 'upstream/main' into gcp-auth-api
sukumargaonkar Jun 13, 2025
2756c32
refactor: update GCP schema names to include Vertex AI platform
sukumargaonkar Jun 13, 2025
a4e725c
refactor: GeminiVertexAI schema to GCPVertexAI
sukumargaonkar Jun 16, 2025
700dc73
Merge remote-tracking branch 'upstream/main' into gcp-auth-api
sukumargaonkar Jun 16, 2025
687d29c
Fix CI
sukumargaonkar Jun 16, 2025
a48254b
Update docs and comments
sukumargaonkar Jun 17, 2025
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
88 changes: 85 additions & 3 deletions api/v1alpha1/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -414,7 +414,7 @@ type AIServiceBackendSpec struct {
type VersionedAPISchema struct {
// Name is the name of the API schema of the AIGatewayRoute or AIServiceBackend.
//
// +kubebuilder:validation:Enum=OpenAI;AWSBedrock;AzureOpenAI
// +kubebuilder:validation:Enum=OpenAI;AWSBedrock;AzureOpenAI;GCPVertexAI;GCPAnthropic
Name APISchema `json:"name"`

// Version is the version of the API schema.
Expand Down Expand Up @@ -450,6 +450,17 @@ const (
//
// https://learn.microsoft.com/en-us/azure/ai-services/openai/reference#api-specs
APISchemaAzureOpenAI APISchema = "AzureOpenAI"
// APISchemaGCPVertexAI is the schema followed by Gemini models hosted on GCP's Vertex AI platform.
// Note: Using this schema requires a BackendSecurityPolicy to be configured and attached,
// as the transformation will use the gcp-region and project-name from the BackendSecurityPolicy.
//
// https://cloud.google.com/vertex-ai/docs/reference/rest/v1/projects.locations.endpoints/generateContent?hl=en
APISchemaGCPVertexAI APISchema = "GCPVertexAI"
// APISchemaGCPAnthropic is the schema followed by Anthropic models hosted on GCP's Vertex AI platform.
// This is majorly the Anthropic API with some GCP specific parameters as described in below URL.
//
// https://docs.anthropic.com/en/api/claude-on-vertex-ai
APISchemaGCPAnthropic APISchema = "GCPAnthropic"
)

const (
Expand All @@ -465,6 +476,7 @@ const (
BackendSecurityPolicyTypeAPIKey BackendSecurityPolicyType = "APIKey"
BackendSecurityPolicyTypeAWSCredentials BackendSecurityPolicyType = "AWSCredentials"
BackendSecurityPolicyTypeAzureCredentials BackendSecurityPolicyType = "AzureCredentials"
BackendSecurityPolicyTypeGCPCredentials BackendSecurityPolicyType = "GCPCredentials"
)

// BackendSecurityPolicy specifies configuration for authentication and authorization rules on the traffic
Expand All @@ -487,9 +499,9 @@ type BackendSecurityPolicy struct {
// Only one type of BackendSecurityPolicy can be defined.
// +kubebuilder:validation:MaxProperties=2
type BackendSecurityPolicySpec struct {
// Type specifies the auth mechanism used to access the provider. Currently, only "APIKey", "AWSCredentials", and "AzureCredentials" are supported.
// Type specifies the type of the backend security policy.
//
// +kubebuilder:validation:Enum=APIKey;AWSCredentials;AzureCredentials
// +kubebuilder:validation:Enum=APIKey;AWSCredentials;AzureCredentials;GCPCredentials
Type BackendSecurityPolicyType `json:"type"`

// APIKey is a mechanism to access a backend(s). The API key will be injected into the Authorization header.
Expand All @@ -506,6 +518,10 @@ type BackendSecurityPolicySpec struct {
//
// +optional
AzureCredentials *BackendSecurityPolicyAzureCredentials `json:"azureCredentials,omitempty"`
// GCPCredentials is a mechanism to access a backend(s). GCP specific logic will be applied.
//
// +optional
GCPCredentials *BackendSecurityPolicyGCPCredentials `json:"gcpCredentials,omitempty"`
}

// BackendSecurityPolicyList contains a list of BackendSecurityPolicy
Expand Down Expand Up @@ -543,6 +559,72 @@ type BackendSecurityPolicyOIDC struct {
Aud string `json:"aud,omitempty"`
}

type GCPWorkLoadIdentityFederationConfig struct {
// ProjectID is the GCP project ID.
//
// +kubebuilder:validation:Required
// +kubebuilder:validation:MinLength=1
ProjectID string `json:"projectID"`
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is ProjectID specific to Federation Config? Would it make sense to bubble this field up if it's needed for all GCP auth

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not sure if other authentication methods would need project-id, so keeping it within federation config for now


// WorkloadIdentityProvider is the external auth provider to be used to authenticate against GCP.
// https://cloud.google.com/iam/docs/workload-identity-federation?hl=en
// Currently only OIDC is supported.
//
// +kubebuilder:validation:Required
WorkloadIdentityProvider GCPWorkloadIdentityProvider `json:"workloadIdentityProvider"`

// WorkloadIdentityPoolName is the name of the workload identity pool defined in GCP.
// https://cloud.google.com/iam/docs/workload-identity-federation?hl=en
//
// +kubebuilder:validation:Required
// +kubebuilder:validation:MinLength=1
WorkloadIdentityPoolName string `json:"workloadIdentityPoolName"`

// ServiceAccountImpersonation is the service account impersonation configuration.
// This is used to impersonate a service account when getting access token.
//
// +optional
ServiceAccountImpersonation *GCPServiceAccountImpersonationConfig `json:"serviceAccountImpersonation,omitempty"`
}

// GCPWorkloadIdentityProvider specifies the external identity provider to be used to authenticate against GCP.
// The external identity provider can be AWS, Microsoft, etc but must be pre-registered in the GCP project
//
// https://cloud.google.com/iam/docs/workload-identity-federation
type GCPWorkloadIdentityProvider struct {
// Name of the external identity provider as registered on Google Cloud Platform.
//
// +kubebuilder:validation:Required
// +kubebuilder:validation:MinLength=1
Name string `json:"name"`

// OIDCProvider is the generic OIDCProvider fields.
//
// +kubebuilder:validation:Required
OIDCProvider BackendSecurityPolicyOIDC `json:"OIDCProvider"`
}

type GCPServiceAccountImpersonationConfig struct {
// ServiceAccountName is the name of the service account to impersonate.
//
// +kubebuilder:validation:Required
// +kubebuilder:validation:MinLength=1
ServiceAccountName string `json:"serviceAccountName"`
// ServiceAccountProjectName is the project name in which the service account is registered.
//
// +kubebuilder:validation:Required
// +kubebuilder:validation:MinLength=1
ServiceAccountProjectName string `json:"serviceAccountProjectName"`
}

// BackendSecurityPolicyGCPCredentials contains the supported authentication mechanisms to access GCP.
type BackendSecurityPolicyGCPCredentials struct {
// WorkLoadIdentityFederationConfig is the configuration for the GCP Workload Identity Federation.
//
// +kubebuilder:validation:Required
WorkLoadIdentityFederationConfig GCPWorkLoadIdentityFederationConfig `json:"workLoadIdentityFederationConfig"`
}

// BackendSecurityPolicyAzureCredentials contains the supported authentication mechanisms to access Azure.
// Only one of ClientSecretRef or OIDCExchangeToken must be specified. Credentials will not be generated if
// neither are set.
Expand Down
73 changes: 73 additions & 0 deletions api/v1alpha1/zz_generated.deepcopy.go

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

73 changes: 73 additions & 0 deletions examples/basic/basic.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,24 @@ spec:
kind: BackendSecurityPolicy
group: aigateway.envoyproxy.io
---
# GCP Example
apiVersion: aigateway.envoyproxy.io/v1alpha1
kind: AIServiceBackend
metadata:
name: envoy-ai-gateway-basic-gcp
namespace: default
spec:
schema:
name: GCPVertexAI
backendRef:
name: envoy-ai-gateway-basic-gcp
kind: Backend
group: gateway.envoyproxy.io
backendSecurityPolicyRef:
name: envoy-ai-gateway-basic-gcp-credentials
kind: BackendSecurityPolicy
group: aigateway.envoyproxy.io
---
apiVersion: aigateway.envoyproxy.io/v1alpha1
kind: AIServiceBackend
metadata:
Expand Down Expand Up @@ -148,6 +166,28 @@ spec:
secretRef:
name: envoy-ai-gateway-basic-aws-credentials
---
apiVersion: aigateway.envoyproxy.io/v1alpha1
kind: BackendSecurityPolicy
metadata:
name: envoy-ai-gateway-basic-gcp-credentials
namespace: default
spec:
type: GCPCredentials
gcpCredentials:
workLoadIdentityFederationConfig:
projectID: GCP_PROJECT_ID # Replace with your GCP project ID
workloadIdentityPoolName: GCP_WORKLOAD_IDENTITY_POOL # Replace with your workload identity pool name
workloadIdentityProvider:
name: GCP_IDENTITY_PROVIDER_NAME # Replace with the identity provider configured with GCP
OIDCProvider:
oidc:
provider:
issuer: GCP_OIDC_PROVIDER_ISSUER # Replace with your OIDC provider issuer
clientID: GCP_OIDC_CLIENT_ID # Replace with your OIDC client ID
clientSecret:
name: envoy-ai-gateway-basic-gcp-client-secret
namespace: default
---
apiVersion: gateway.envoyproxy.io/v1alpha1
kind: Backend
metadata:
Expand All @@ -172,6 +212,17 @@ spec:
---
apiVersion: gateway.envoyproxy.io/v1alpha1
kind: Backend
metadata:
name: envoy-ai-gateway-basic-gcp
namespace: default
spec:
endpoints:
- fqdn:
hostname: us-central1-aiplatform.googleapis.com
port: 443
---
apiVersion: gateway.envoyproxy.io/v1alpha1
kind: Backend
metadata:
name: envoy-ai-gateway-basic-azure
namespace: default
Expand Down Expand Up @@ -211,6 +262,20 @@ spec:
---
apiVersion: gateway.networking.k8s.io/v1alpha3
kind: BackendTLSPolicy
metadata:
name: envoy-ai-gateway-basic-gcp-tls
namespace: default
spec:
targetRefs:
- group: 'gateway.envoyproxy.io'
kind: Backend
name: envoy-ai-gateway-basic-gcp
validation:
wellKnownCACertificates: "System"
hostname: us-central1-aiplatform.googleapis.com
---
apiVersion: gateway.networking.k8s.io/v1alpha3
kind: BackendTLSPolicy
metadata:
name: envoy-ai-gateway-basic-azure-tls
namespace: default
Expand Down Expand Up @@ -254,6 +319,14 @@ stringData:
aws_access_key_id = AWS_ACCESS_KEY_ID
aws_secret_access_key = AWS_SECRET_ACCESS_KEY
---
apiVersion: v1
kind: Secret
metadata:
name: envoy-ai-gateway-basic-gcp-client-secret
namespace: default
stringData:
client-secret: "GCP_OIDC_CLIENT_SECRET" # Replace with your OIDC client secret
---
apiVersion: aigateway.envoyproxy.io/v1alpha1
kind: AIServiceBackend
metadata:
Expand Down
12 changes: 12 additions & 0 deletions filterapi/filterconfig.go
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,8 @@ type BackendAuth struct {
AWSAuth *AWSAuth `json:"aws,omitempty"`
// AzureAuth specifies the location of Azure access token file.
AzureAuth *AzureAuth `json:"azure,omitempty"`
// GCPAuth specifies the location of GCP credential file.
GCPAuth *GCPAuth `json:"gcp,omitempty"`
}

// AWSAuth defines the credentials needed to access AWS.
Expand All @@ -224,6 +226,16 @@ type AzureAuth struct {
AccessToken string `json:"accessToken"`
}

// GCPAuth defines the file containing GCP credential that will be mounted to the external proc.
type GCPAuth struct {
// AccessToken is the access token as a literal string.
AccessToken string `json:"accessToken"`
// Region is the GCP region to use for the request.
Region string `json:"region"`
// ProjectName is the GCP project name to use for the request.
ProjectName string `json:"projectName"`
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How will region and project be used in the extproc?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The region and project-id are required while transforming request path
https://<region>-aiplatform.googleapis.com/v1/projects/<project-id>/locations/<region>/publishers/google/models/<model-name>:generateContent

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

then maybe ProjectID instead of ProjectName

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tried using project ID in the request url, but kept getting IAM_PERMISSION_DENIED error
not sure if that is an account specific configuration issue or GCP just doesn't like project ID instead of project-name

if future project name is found to be acceptable, we can add that as another field and accept either of them as valid config

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if project name is currently required on the url path, then it needs to be added to the BackendSecurityPolicy as well?

}

// UnmarshalConfigYaml reads the file at the given path and unmarshals it into a Config struct.
func UnmarshalConfigYaml(path string) (*Config, error) {
raw, err := os.ReadFile(path)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -505,6 +505,8 @@ spec:
- OpenAI
- AWSBedrock
- AzureOpenAI
- GCPVertexAI
- GCPAnthropic
type: string
version:
description: |-
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,8 @@ spec:
- OpenAI
- AWSBedrock
- AzureOpenAI
- GCPVertexAI
- GCPAnthropic
type: string
version:
description: |-
Expand Down
Loading