From 5b9ebea5bc513d14f1b48a4abf72a086d957d95b Mon Sep 17 00:00:00 2001 From: David Alger Date: Mon, 1 Apr 2024 09:28:50 -0500 Subject: [PATCH] api: gRPC Access Log Service (ALS) logging sink Signed-off-by: David Alger --- api/v1alpha1/accesslogging_types.go | 66 ++++++++- api/v1alpha1/zz_generated.deepcopy.go | 56 +++++++ .../gateway.envoyproxy.io_envoyproxies.yaml | 137 ++++++++++++++++++ site/content/en/latest/api/extension_types.md | 55 +++++++ 4 files changed, 313 insertions(+), 1 deletion(-) diff --git a/api/v1alpha1/accesslogging_types.go b/api/v1alpha1/accesslogging_types.go index 483a224fab4..64b6ea391d5 100644 --- a/api/v1alpha1/accesslogging_types.go +++ b/api/v1alpha1/accesslogging_types.go @@ -5,6 +5,8 @@ package v1alpha1 +import gwapiv1 "sigs.k8s.io/gateway-api/apis/v1" + type ProxyAccessLog struct { // Disable disables access logging for managed proxies if set to true. Disable bool `json:"disable,omitempty"` @@ -60,6 +62,10 @@ type ProxyAccessLogFormat struct { type ProxyAccessLogSinkType string const ( + // ProxyAccessLogSinkTypeALS defines the gRPC Access Log Service (ALS) sink. + // The service must implement the Envoy gRPC Access Log Service streaming API: + // https://www.envoyproxy.io/docs/envoy/latest/api-v3/service/accesslog/v3/als.proto + ProxyAccessLogSinkTypeALS ProxyAccessLogSinkType = "ALS" // ProxyAccessLogSinkTypeFile defines the file accesslog sink. ProxyAccessLogSinkTypeFile ProxyAccessLogSinkType = "File" // ProxyAccessLogSinkTypeOpenTelemetry defines the OpenTelemetry accesslog sink. @@ -71,13 +77,17 @@ const ( // ProxyAccessLogSink defines the sink of accesslog. // +union // +// +kubebuilder:validation:XValidation:rule="self.type == 'ALS' ? has(self.als) : !has(self.als)",message="If AccessLogSink type is ALS, als field needs to be set." // +kubebuilder:validation:XValidation:rule="self.type == 'File' ? has(self.file) : !has(self.file)",message="If AccessLogSink type is File, file field needs to be set." // +kubebuilder:validation:XValidation:rule="self.type == 'OpenTelemetry' ? has(self.openTelemetry) : !has(self.openTelemetry)",message="If AccessLogSink type is OpenTelemetry, openTelemetry field needs to be set." type ProxyAccessLogSink struct { // Type defines the type of accesslog sink. - // +kubebuilder:validation:Enum=File;OpenTelemetry + // +kubebuilder:validation:Enum=ALS;File;OpenTelemetry // +unionDiscriminator Type ProxyAccessLogSinkType `json:"type,omitempty"` + // ALS defines the gRPC Access Log Service (ALS) sink. + // +optional + ALS *ALSEnvoyProxyAccessLog `json:"als,omitempty"` // File defines the file accesslog sink. // +optional File *FileEnvoyProxyAccessLog `json:"file,omitempty"` @@ -86,6 +96,60 @@ type ProxyAccessLogSink struct { OpenTelemetry *OpenTelemetryEnvoyProxyAccessLog `json:"openTelemetry,omitempty"` } +type ALSEnvoyProxyAccessLogType string + +const ( + // ALSEnvoyProxyAccessLogTypeHTTP defines the HTTP access log type and will populate StreamAccessLogsMessage.http_logs. + ALSEnvoyProxyAccessLogTypeHTTP ALSEnvoyProxyAccessLogType = "HTTP" + // ALSEnvoyProxyAccessLogTypeTCP defines the TCP access log type and will populate StreamAccessLogsMessage.tcp_logs. + ALSEnvoyProxyAccessLogTypeTCP ALSEnvoyProxyAccessLogType = "TCP" +) + +// ALSEnvoyProxyAccessLog defines the gRPC Access Log Service (ALS) sink. +// The service must implement the Envoy gRPC Access Log Service streaming API: +// https://www.envoyproxy.io/docs/envoy/latest/api-v3/service/accesslog/v3/als.proto +// Access log format information is passed in the form of gRPC metadata when the +// stream is established. Specifically, the following metadata is passed: +// +// - `x-accesslog-text` - The access log format string when a Text format is used. +// +// - `x-accesslog-attr` - JSON encoded key/value pairs when a JSON format is used. +// +// +kubebuilder:validation:XValidation:message="BackendRef only supports Service Kind.",rule="!has(self.backendRef.kind) || self.backendRef.kind == 'Service'" +// +kubebuilder:validation:XValidation:rule="self.type == 'HTTP' || !has(self.http)",message="The http field may only be set when type is HTTP." +type ALSEnvoyProxyAccessLog struct { + // BackendRef references a Kubernetes object that represents the gRPC service to which + // the access logs will be sent. Currently only Service is supported. + BackendRef gwapiv1.BackendObjectReference `json:"backendRef,omitempty"` + // LogName defines the friendly name of the access log to be returned in + // StreamAccessLogsMessage.Identifier. This allows the access log server + // to differentiate between different access logs coming from the same Envoy. + // +optional + // +kubebuilder:validation:MinLength=1 + // +kubebuilder:default="accesslog" + LogName string `json:"logName,omitempty"` + // Type defines the type of accesslog. Supported types are "HTTP" and "TCP". Defaults to "HTTP" when not specified. + // +kubebuilder:validation:Enum=HTTP;TCP + // +unionDiscriminator + // +kubebuilder:default="HTTP" + Type ALSEnvoyProxyAccessLogType `json:"type,omitempty"` + // HTTP defines additional configuration specific to HTTP access logs. + // +optional + HTTP *ALSEnvoyProxyHTTPAccessLogConfig `json:"http,omitempty"` +} + +type ALSEnvoyProxyHTTPAccessLogConfig struct { + // RequestHeaders defines request headers to include in log entries sent to the access log service. + // +optional + RequestHeaders []string `json:"requestHeaders,omitempty" yaml:"requestHeaders,omitempty"` + // ResponseHeaders defines response headers to include in log entries sent to the access log service. + // +optional + ResponseHeaders []string `json:"responseHeaders,omitempty" yaml:"responseHeaders,omitempty"` + // ResponseTrailers defines response trailers to include in log entries sent to the access log service. + // +optional + ResponseTrailers []string `json:"responseTrailers,omitempty" yaml:"responseTrailers,omitempty"` +} + type FileEnvoyProxyAccessLog struct { // Path defines the file path used to expose envoy access log(e.g. /dev/stdout). // +kubebuilder:validation:MinLength=1 diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index d170dcf1f43..0d532b2be9f 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -19,6 +19,57 @@ import ( "sigs.k8s.io/gateway-api/apis/v1" ) +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ALSEnvoyProxyAccessLog) DeepCopyInto(out *ALSEnvoyProxyAccessLog) { + *out = *in + in.BackendRef.DeepCopyInto(&out.BackendRef) + if in.HTTP != nil { + in, out := &in.HTTP, &out.HTTP + *out = new(ALSEnvoyProxyHTTPAccessLogConfig) + (*in).DeepCopyInto(*out) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ALSEnvoyProxyAccessLog. +func (in *ALSEnvoyProxyAccessLog) DeepCopy() *ALSEnvoyProxyAccessLog { + if in == nil { + return nil + } + out := new(ALSEnvoyProxyAccessLog) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ALSEnvoyProxyHTTPAccessLogConfig) DeepCopyInto(out *ALSEnvoyProxyHTTPAccessLogConfig) { + *out = *in + if in.RequestHeaders != nil { + in, out := &in.RequestHeaders, &out.RequestHeaders + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.ResponseHeaders != nil { + in, out := &in.ResponseHeaders, &out.ResponseHeaders + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.ResponseTrailers != nil { + in, out := &in.ResponseTrailers, &out.ResponseTrailers + *out = make([]string, len(*in)) + copy(*out, *in) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ALSEnvoyProxyHTTPAccessLogConfig. +func (in *ALSEnvoyProxyHTTPAccessLogConfig) DeepCopy() *ALSEnvoyProxyHTTPAccessLogConfig { + if in == nil { + return nil + } + out := new(ALSEnvoyProxyHTTPAccessLogConfig) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *ActiveHealthCheck) DeepCopyInto(out *ActiveHealthCheck) { *out = *in @@ -2804,6 +2855,11 @@ func (in *ProxyAccessLogSetting) DeepCopy() *ProxyAccessLogSetting { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *ProxyAccessLogSink) DeepCopyInto(out *ProxyAccessLogSink) { *out = *in + if in.ALS != nil { + in, out := &in.ALS, &out.ALS + *out = new(ALSEnvoyProxyAccessLog) + (*in).DeepCopyInto(*out) + } if in.File != nil { in, out := &in.File, &out.File *out = new(FileEnvoyProxyAccessLog) diff --git a/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_envoyproxies.yaml b/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_envoyproxies.yaml index 4e092a8e739..98c2fcf0d68 100644 --- a/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_envoyproxies.yaml +++ b/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_envoyproxies.yaml @@ -5886,6 +5886,139 @@ spec: description: ProxyAccessLogSink defines the sink of accesslog. properties: + als: + description: ALS defines the gRPC Access Log Service + (ALS) sink. + properties: + backendRef: + description: |- + BackendRef references a Kubernetes object that represents the gRPC service to which + the access logs will be sent. Currently only Service is supported. + properties: + group: + default: "" + description: |- + Group is the group of the referent. For example, "gateway.networking.k8s.io". + When unspecified or empty string, core API group is inferred. + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + default: Service + description: |- + Kind is the Kubernetes resource kind of the referent. For example + "Service". + + + Defaults to "Service" when not specified. + + + ExternalName services can refer to CNAME DNS records that may live + outside of the cluster and as such are difficult to reason about in + terms of conformance. They also may not be safe to forward to (see + CVE-2021-25740 for more information). Implementations SHOULD NOT + support ExternalName Services. + + + Support: Core (Services with a type other than ExternalName) + + + Support: Implementation-specific (Services with type ExternalName) + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + name: + description: Name is the name of the referent. + maxLength: 253 + minLength: 1 + type: string + namespace: + description: |- + Namespace is the namespace of the backend. When unspecified, the local + namespace is inferred. + + + Note that when a namespace different than the local namespace is specified, + a ReferenceGrant object is required in the referent namespace to allow that + namespace's owner to accept the reference. See the ReferenceGrant + documentation for details. + + + Support: Core + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + port: + description: |- + Port specifies the destination port number to use for this resource. + Port is required when the referent is a Kubernetes Service. In this + case, the port number is the service port number, not the target port. + For other resources, destination port might be derived from the referent + resource or this field. + format: int32 + maximum: 65535 + minimum: 1 + type: integer + required: + - name + type: object + x-kubernetes-validations: + - message: Must have port for Service reference + rule: '(size(self.group) == 0 && self.kind + == ''Service'') ? has(self.port) : true' + http: + description: HTTP defines additional configuration + specific to HTTP access logs. + properties: + requestHeaders: + description: RequestHeaders defines request + headers to include in log entries sent + to the access log service. + items: + type: string + type: array + responseHeaders: + description: ResponseHeaders defines response + headers to include in log entries sent + to the access log service. + items: + type: string + type: array + responseTrailers: + description: ResponseTrailers defines + response trailers to include in log + entries sent to the access log service. + items: + type: string + type: array + type: object + logName: + default: accesslog + description: |- + LogName defines the friendly name of the access log to be returned in + StreamAccessLogsMessage.Identifier. This allows the access log server + to differentiate between different access logs coming from the same Envoy. + minLength: 1 + type: string + type: + default: HTTP + description: Type defines the type of accesslog. + Supported types are "HTTP" and "TCP". Defaults + to "HTTP" when not specified. + enum: + - HTTP + - TCP + type: string + type: object + x-kubernetes-validations: + - message: BackendRef only supports Service Kind. + rule: '!has(self.backendRef.kind) || self.backendRef.kind + == ''Service''' + - message: The http field may only be set when + type is HTTP. + rule: self.type == 'HTTP' || !has(self.http) file: description: File defines the file accesslog sink. properties: @@ -5924,11 +6057,15 @@ spec: description: Type defines the type of accesslog sink. enum: + - ALS - File - OpenTelemetry type: string type: object x-kubernetes-validations: + - message: If AccessLogSink type is ALS, als field + needs to be set. + rule: 'self.type == ''ALS'' ? has(self.als) : !has(self.als)' - message: If AccessLogSink type is File, file field needs to be set. rule: 'self.type == ''File'' ? has(self.file) : diff --git a/site/content/en/latest/api/extension_types.md b/site/content/en/latest/api/extension_types.md index a289a7530b8..6f69cfc2a89 100644 --- a/site/content/en/latest/api/extension_types.md +++ b/site/content/en/latest/api/extension_types.md @@ -40,6 +40,60 @@ _Appears in:_ +#### ALSEnvoyProxyAccessLog + + + +ALSEnvoyProxyAccessLog defines the gRPC Access Log Service (ALS) sink. +The service must implement the Envoy gRPC Access Log Service streaming API: +https://www.envoyproxy.io/docs/envoy/latest/api-v3/service/accesslog/v3/als.proto +Access log format information is passed in the form of gRPC metadata when the +stream is established. Specifically, the following metadata is passed: + + +- `x-accesslog-text` - The access log format string when a Text format is used. + + +- `x-accesslog-attr` - JSON encoded key/value pairs when a JSON format is used. + +_Appears in:_ +- [ProxyAccessLogSink](#proxyaccesslogsink) + +| Field | Type | Required | Description | +| --- | --- | --- | --- | +| `backendRef` | _[BackendObjectReference](#backendobjectreference)_ | true | BackendRef references a Kubernetes object that represents the gRPC service to which
the access logs will be sent. Currently only Service is supported. | +| `logName` | _string_ | false | LogName defines the friendly name of the access log to be returned in
StreamAccessLogsMessage.Identifier. This allows the access log server
to differentiate between different access logs coming from the same Envoy. | +| `type` | _[ALSEnvoyProxyAccessLogType](#alsenvoyproxyaccesslogtype)_ | true | Type defines the type of accesslog. Supported types are "HTTP" and "TCP". Defaults to "HTTP" when not specified. | +| `http` | _[ALSEnvoyProxyHTTPAccessLogConfig](#alsenvoyproxyhttpaccesslogconfig)_ | false | HTTP defines additional configuration specific to HTTP access logs. | + + +#### ALSEnvoyProxyAccessLogType + +_Underlying type:_ _string_ + + + +_Appears in:_ +- [ALSEnvoyProxyAccessLog](#alsenvoyproxyaccesslog) + + + +#### ALSEnvoyProxyHTTPAccessLogConfig + + + + + +_Appears in:_ +- [ALSEnvoyProxyAccessLog](#alsenvoyproxyaccesslog) + +| Field | Type | Required | Description | +| --- | --- | --- | --- | +| `requestHeaders` | _string array_ | false | RequestHeaders defines request headers to include in log entries sent to the access log service. | +| `responseHeaders` | _string array_ | false | ResponseHeaders defines response headers to include in log entries sent to the access log service. | +| `responseTrailers` | _string array_ | false | ResponseTrailers defines response trailers to include in log entries sent to the access log service. | + + #### ActiveHealthCheck @@ -1974,6 +2028,7 @@ _Appears in:_ | Field | Type | Required | Description | | --- | --- | --- | --- | | `type` | _[ProxyAccessLogSinkType](#proxyaccesslogsinktype)_ | true | Type defines the type of accesslog sink. | +| `als` | _[ALSEnvoyProxyAccessLog](#alsenvoyproxyaccesslog)_ | false | ALS defines the gRPC Access Log Service (ALS) sink. | | `file` | _[FileEnvoyProxyAccessLog](#fileenvoyproxyaccesslog)_ | false | File defines the file accesslog sink. | | `openTelemetry` | _[OpenTelemetryEnvoyProxyAccessLog](#opentelemetryenvoyproxyaccesslog)_ | false | OpenTelemetry defines the OpenTelemetry accesslog sink. |