Skip to content

Commit

Permalink
Merge branch 'master' into paths-support
Browse files Browse the repository at this point in the history
  • Loading branch information
druminski committed Aug 12, 2024
2 parents 4864cfd + fe83881 commit 2d10f5a
Show file tree
Hide file tree
Showing 25 changed files with 877 additions and 217 deletions.
16 changes: 16 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,22 @@
Lists all changes with user impact.
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/).

## [0.20.19]
### Changed
- Added http compression filter properties to node metadata
-
## [0.20.18]
### Changed
- Added http compression filter configuration

## [0.20.17]
### Fixed
- Fix JWT provider configuration to not impact lds cache
- Add missing methods in lua scripts to remove logs about it

## [0.20.16]
### Changed
- Add JWT failure reason to metadata and use it in jwt-status field on denied requests

## [0.21.0]
### Changed
Expand Down
182 changes: 98 additions & 84 deletions docs/configuration.md

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ sealed class Group {
abstract val proxySettings: ProxySettings
abstract val pathNormalizationConfig: PathNormalizationConfig
abstract val listenersConfig: ListenersConfig?
abstract val compressionConfig: CompressionConfig
}

data class ServicesGroup(
Expand All @@ -18,6 +19,7 @@ data class ServicesGroup(
override val proxySettings: ProxySettings = ProxySettings(),
override val pathNormalizationConfig: PathNormalizationConfig = PathNormalizationConfig(),
override val listenersConfig: ListenersConfig? = null,
override val compressionConfig: CompressionConfig = CompressionConfig(),
) : Group()

data class AllServicesGroup(
Expand All @@ -26,15 +28,26 @@ data class AllServicesGroup(
override val discoveryServiceName: String? = null,
override val proxySettings: ProxySettings = ProxySettings(),
override val pathNormalizationConfig: PathNormalizationConfig = PathNormalizationConfig(),
override val listenersConfig: ListenersConfig? = null
) : Group()
override val listenersConfig: ListenersConfig? = null,
override val compressionConfig: CompressionConfig = CompressionConfig(),
) : Group()

data class PathNormalizationConfig(
val normalizationEnabled: Boolean? = null,
val mergeSlashes: Boolean? = null,
val pathWithEscapedSlashesAction: String? = null
)

data class CompressionConfig(
val gzip: Compressor? = null,
val brotli: Compressor? = null,
)

data class Compressor(
val enabled: Boolean? = null,
val quality: Int? = null,
)

data class ListenersConfig(
val ingressHost: String,
val ingressPort: Int,
Expand All @@ -48,6 +61,7 @@ data class ListenersConfig(
val accessLogPath: String = defaultAccessLogPath,
val addUpstreamExternalAddressHeader: Boolean = defaultAddUpstreamExternalAddressHeader,
val addUpstreamServiceTags: AddUpstreamServiceTagsCondition = AddUpstreamServiceTagsCondition.NEVER,
val addJwtFailureStatus: Boolean = true,
val accessLogFilterSettings: AccessLogFilterSettings,
val hasStaticSecretsDefined: Boolean = defaultHasStaticSecretsDefined,
val useTransparentProxy: Boolean = defaultUseTransparentProxy
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ import io.envoyproxy.envoy.config.core.v3.Node as NodeV3

@Suppress("MagicNumber")
val MIN_ENVOY_VERSION_SUPPORTING_UPSTREAM_METADATA = envoyVersion(1, 24)
@Suppress("MagicNumber")
val MIN_ENVOY_VERSION_SUPPORTING_JWT_FAILURE_STATUS = envoyVersion(1, 26)

class MetadataNodeGroup(
val properties: SnapshotProperties
Expand Down Expand Up @@ -133,6 +135,8 @@ class MetadataNodeGroup(
val useTransparentProxy = metadata.fieldsMap["use_transparent_proxy"]?.boolValue
?: ListenersConfig.defaultUseTransparentProxy

val addJwtFailureStatus = envoyVersion.version >= MIN_ENVOY_VERSION_SUPPORTING_JWT_FAILURE_STATUS

return ListenersConfig(
listenersHostPort.ingressHost,
listenersHostPort.ingressPort,
Expand All @@ -146,6 +150,7 @@ class MetadataNodeGroup(
accessLogPath,
addUpstreamExternalAddressHeader,
addUpstreamServiceTags,
addJwtFailureStatus,
accessLogFilterSettings,
hasStaticSecretsDefined,
useTransparentProxy
Expand Down Expand Up @@ -180,7 +185,8 @@ class MetadataNodeGroup(
discoveryServiceName,
proxySettings,
nodeMetadata.pathNormalizationConfig,
listenersConfig
listenersConfig,
nodeMetadata.compressionConfig
)
else ->
ServicesGroup(
Expand All @@ -189,7 +195,8 @@ class MetadataNodeGroup(
discoveryServiceName,
proxySettings,
nodeMetadata.pathNormalizationConfig,
listenersConfig
listenersConfig,
nodeMetadata.compressionConfig
)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import io.grpc.Status
import pl.allegro.tech.servicemesh.envoycontrol.groups.ClientWithSelector.Companion.decomposeClient
import pl.allegro.tech.servicemesh.envoycontrol.snapshot.AccessLogFiltersProperties
import pl.allegro.tech.servicemesh.envoycontrol.snapshot.CommonHttpProperties
import pl.allegro.tech.servicemesh.envoycontrol.snapshot.CompressorProperties
import pl.allegro.tech.servicemesh.envoycontrol.snapshot.RetryPolicyProperties
import pl.allegro.tech.servicemesh.envoycontrol.snapshot.SnapshotProperties
import pl.allegro.tech.servicemesh.envoycontrol.utils.AccessLogFilterParser
Expand All @@ -35,6 +36,7 @@ class NodeMetadata(metadata: Struct, properties: SnapshotProperties) {

val pathNormalizationConfig = getPathNormalization(metadata.fieldsMap["path_normalization"], properties)
val proxySettings: ProxySettings = ProxySettings(metadata.fieldsMap["proxy_settings"], properties)
val compressionConfig: CompressionConfig = getCompressionSettings(metadata.fieldsMap["compression"], properties)
}

data class AccessLogFilterSettings(val proto: Value?, val properties: AccessLogFiltersProperties) {
Expand Down Expand Up @@ -86,6 +88,22 @@ fun getPathNormalization(proto: Value?, snapshotProperties: SnapshotProperties):
)
}

fun getCompressionSettings(proto: Value?, snapshotProperties: SnapshotProperties): CompressionConfig {
val defaultCompressionConfig = CompressionConfig(
Compressor(snapshotProperties.compression.gzip.enabled, snapshotProperties.compression.gzip.quality),
Compressor(snapshotProperties.compression.brotli.enabled, snapshotProperties.compression.brotli.quality)
)
if (proto == null) {
return defaultCompressionConfig
}
return CompressionConfig(
proto.field("gzip")?.toCompressorProperties(snapshotProperties.compression.gzip)
?: defaultCompressionConfig.gzip,
proto.field("brotli")?.toCompressorProperties(snapshotProperties.compression.brotli)
?: defaultCompressionConfig.brotli,
)
}

private fun getCommunicationMode(proto: Value?): CommunicationMode {
val ads = proto
?.boolValue
Expand Down Expand Up @@ -344,6 +362,15 @@ fun Value?.toIncoming(properties: SnapshotProperties): Incoming {
)
}

fun Value?.toCompressorProperties(properties: CompressorProperties): Compressor {
val enabled = this?.field("enabled")?.boolValue
val quality = this?.field("quality")?.numberValue?.toInt()
return Compressor(
enabled ?: properties.enabled,
quality ?: properties.quality
)
}

fun Value?.toUnlistedPolicy() = this?.stringValue
?.takeIf { it.isNotEmpty() }
?.let {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,15 @@ class SnapshotProperties {
var retryPolicy = RetryPolicyProperties()
var tcpDumpsEnabled: Boolean = true
var shouldAuditGlobalSnapshot: Boolean = true
var compression: CompressionProperties = CompressionProperties()
}

class PathNormalizationProperties {
var enabled = true
var mergeSlashes = true
var pathWithEscapedSlashesAction = "KEEP_UNCHANGED"
}

class MetricsProperties {
var cacheSetSnapshot = false
}
Expand All @@ -64,7 +66,7 @@ class AccessLogProperties {
var enabled = false
var timeFormat = "%START_TIME(%FT%T.%3fZ)%"
var messageFormat = "%PROTOCOL% %REQ(:METHOD)% %REQ(:authority)% %REQ(:PATH)% " +
"%DOWNSTREAM_REMOTE_ADDRESS% -> %UPSTREAM_HOST%"
"%DOWNSTREAM_REMOTE_ADDRESS% -> %UPSTREAM_HOST%"
var level = "TRACE"
var logger = "envoy.AccessLog"
var customFields = mapOf<String, String>()
Expand Down Expand Up @@ -130,6 +132,7 @@ class ClientsListsProperties {
var defaultClientsList: List<String> = emptyList()
var customClientsLists: Map<String, List<String>> = mapOf()
}

class TlsProtocolProperties {
var cipherSuites: List<String> = listOf("ECDHE-ECDSA-AES128-GCM-SHA256", "ECDHE-RSA-AES128-GCM-SHA256")
var minimumVersion = TlsParameters.TlsProtocol.TLSv1_2
Expand Down Expand Up @@ -377,6 +380,21 @@ class DynamicForwardProxyProperties {
var connectionTimeout = Duration.ofSeconds(1)
}

class CompressionProperties {
var gzip = CompressorProperties()
var brotli = CompressorProperties()
var minContentLength = 100
var disableOnEtagHeader = true
var requestCompressionEnabled = false
var responseCompressionEnabled = false
}

class CompressorProperties {
var enabled = false
var quality = 1
var chooseFirst = true
}

data class OAuthProvider(
var jwksUri: URI = URI.create("http://localhost"),
var createCluster: Boolean = false,
Expand All @@ -391,6 +409,8 @@ class JwtFilterProperties {
var forwardJwt: Boolean = true
var forwardPayloadHeader = "x-oauth-token-validated"
var payloadInMetadata = "jwt"
var failedStatusInMetadata = "jwt_failure_reason"
var failedStatusInMetadataEnabled = true
var fieldRequiredInToken = "exp"
var defaultVerificationType = OAuth.Verification.OFFLINE
var defaultOAuthPolicy = OAuth.Policy.STRICT
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
package pl.allegro.tech.servicemesh.envoycontrol.snapshot.resource.listeners.filters

import com.google.protobuf.BoolValue
import com.google.protobuf.UInt32Value
import io.envoyproxy.envoy.config.core.v3.RuntimeFeatureFlag
import io.envoyproxy.envoy.config.core.v3.TypedExtensionConfig
import io.envoyproxy.envoy.config.filter.http.gzip.v2.Gzip.CompressionLevel.Enum.BEST_VALUE
import io.envoyproxy.envoy.extensions.compression.brotli.compressor.v3.Brotli
import io.envoyproxy.envoy.extensions.compression.gzip.compressor.v3.Gzip
import io.envoyproxy.envoy.extensions.filters.http.compressor.v3.Compressor
import io.envoyproxy.envoy.extensions.filters.network.http_connection_manager.v3.HttpFilter
import pl.allegro.tech.servicemesh.envoycontrol.groups.Group
import pl.allegro.tech.servicemesh.envoycontrol.snapshot.SnapshotProperties

class CompressionFilterFactory(val properties: SnapshotProperties) {

fun gzipCompressionFilter(group: Group): HttpFilter? {
val compressionLevel = Gzip.CompressionLevel.forNumber(
group.compressionConfig.gzip?.quality
?: properties.compression.gzip.quality
) ?: Gzip.CompressionLevel.forNumber(BEST_VALUE)
return if (group.compressionConfig.gzip?.enabled == true) {
compressionFilter(
TypedExtensionConfig.newBuilder()
.setName("envoy.compression.gzip.compressor")
.setTypedConfig(
com.google.protobuf.Any.pack(
Gzip.newBuilder()
.setCompressionStrategy(Gzip.CompressionStrategy.DEFAULT_STRATEGY)
.setCompressionLevel(compressionLevel)
.build()
)
),
properties.compression.gzip.chooseFirst
)
} else null
}

fun brotliCompressionFilter(group: Group): HttpFilter? {
val compressionLevel = group.compressionConfig.brotli?.quality ?: properties.compression.brotli.quality
return if (group.compressionConfig.brotli?.enabled == true) {
compressionFilter(
TypedExtensionConfig.newBuilder()
.setName("envoy.compression.brotli.compressor")
.setTypedConfig(
com.google.protobuf.Any.pack(
Brotli.newBuilder()
.setQuality(UInt32Value.of(compressionLevel))
.build()
)
),
properties.compression.brotli.chooseFirst
)
} else null
}

private fun compressionFilter(library: TypedExtensionConfig.Builder, chooseFirst: Boolean) =
HttpFilter.newBuilder()
.setName("envoy.filters.http.compressor")
.setTypedConfig(
com.google.protobuf.Any.pack(
Compressor.newBuilder()
.setChooseFirst(chooseFirst)
.setRequestDirectionConfig(
Compressor.RequestDirectionConfig.newBuilder()
.setCommonConfig(
commonDirectionConfig(
"request_compressor_enabled",
properties.compression.requestCompressionEnabled
)
)
).setResponseDirectionConfig(
Compressor.ResponseDirectionConfig.newBuilder()
.setCommonConfig(
commonDirectionConfig(
"response_compressor_enabled",
properties.compression.responseCompressionEnabled
)
)
.setDisableOnEtagHeader(properties.compression.disableOnEtagHeader)
)
.setCompressorLibrary(library)
.build()
)
).build()

private fun commonDirectionConfig(runtimeKey: String, defaultValue: Boolean) =
Compressor.CommonDirectionConfig.newBuilder()
.setEnabled(
RuntimeFeatureFlag.newBuilder().setRuntimeKey(runtimeKey)
.setDefaultValue(BoolValue.of(defaultValue))
)
.setMinContentLength(UInt32Value.of(properties.compression.minContentLength))
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ class EnvoyDefaultFilters(
properties = snapshotProperties.routing.serviceTags
)

private val compressionFilterFactory = CompressionFilterFactory(snapshotProperties)

private val defaultServiceTagHeaderToMetadataFilterRules = serviceTagFilterFactory.headerToMetadataFilterRules()
private val defaultHeaderToMetadataConfig = headerToMetadataConfig(defaultServiceTagHeaderToMetadataFilterRules)
private val headerToMetadataHttpFilter = headerToMetadataHttpFilter(defaultHeaderToMetadataConfig)
Expand Down Expand Up @@ -62,8 +64,21 @@ class EnvoyDefaultFilters(
val defaultAuthorizationHeaderFilter = { _: Group, _: GlobalSnapshot ->
authorizationHeaderToMetadataFilter()
}

val defaultGzipCompressionFilter = { group: Group, _: GlobalSnapshot ->
compressionFilterFactory.gzipCompressionFilter(group)
}

val defaultBrotliCompressionFilter = { group: Group, _: GlobalSnapshot ->
compressionFilterFactory.brotliCompressionFilter(group)
}

val defaultEgressFilters = listOf(
defaultHeaderToMetadataFilter, defaultServiceTagFilter, defaultEnvoyRouterHttpFilter
defaultHeaderToMetadataFilter,
defaultServiceTagFilter,
defaultGzipCompressionFilter,
defaultBrotliCompressionFilter,
defaultEnvoyRouterHttpFilter,
)

val defaultCurrentZoneHeaderFilter = { _: Group, _: GlobalSnapshot ->
Expand Down
Loading

0 comments on commit 2d10f5a

Please sign in to comment.