diff --git a/gateway/enforcer/Dockerfile b/gateway/enforcer/Dockerfile index 268cda714f..135633e714 100644 --- a/gateway/enforcer/Dockerfile +++ b/gateway/enforcer/Dockerfile @@ -1,5 +1,5 @@ # -------------------------------------------------------------------- -# Copyright (c) 2024, WSO2 LLC. (http://wso2.com) All Rights Reserved. +# Copyright (c) 2022, WSO2 LLC. (http://wso2.com) All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -14,101 +14,43 @@ # limitations under the License. # ----------------------------------------------------------------------- -FROM ubuntu:24.10 - -ENV LANG='en_US.UTF-8' LANGUAGE='en_US:en' LC_ALL='en_US.UTF-8' - -# Upgrade Ubuntu Dependencies -RUN apt-get update \ - && apt-get upgrade -y - -# install JDK Dependencies -RUN apt-get update \ - && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends tzdata curl wget ca-certificates fontconfig locales \ - && echo "en_US.UTF-8 UTF-8" >> /etc/locale.gen \ - && locale-gen en_US.UTF-8 \ - && rm -rf /var/lib/apt/lists/* - -ENV JAVA_VERSION jdk-17.0.8.1+1 - -RUN set -eux; \ - ARCH="$(dpkg --print-architecture)"; \ - case "${ARCH}" in \ - amd64|i386:x86-64) \ - ESUM='ab68857594792474a3049ede09ea1178e42df29803a6a41be771794f571b2d4e'; \ - BINARY_URL='https://github.com/adoptium/temurin17-binaries/releases/download/jdk-17.0.8.1%2B1/OpenJDK17U-jre_x64_linux_hotspot_17.0.8.1_1.tar.gz'; \ - ;; \ - aarch64|arm64) \ - ESUM='0a1c5c9ee9d20832c87bd1e99a4c4a96947b59bb35c72683fe895d705f202737'; \ - BINARY_URL='https://github.com/adoptium/temurin17-binaries/releases/download/jdk-17.0.8.1%2B1/OpenJDK17U-jre_aarch64_linux_hotspot_17.0.8.1_1.tar.gz'; \ - ;; \ - *) \ - echo "Unsupported arch: ${ARCH}"; \ - exit 1; \ - ;; \ - esac; \ - curl -LfsSo /tmp/openjdk.tar.gz ${BINARY_URL}; \ - echo "${ESUM} */tmp/openjdk.tar.gz" | sha256sum -c -; \ - mkdir -p /opt/java/openjdk; \ - cd /opt/java/openjdk; \ - tar -xf /tmp/openjdk.tar.gz --strip-components=1; \ - rm -rf /tmp/openjdk.tar.gz; - -ENV JAVA_HOME=/opt/java/openjdk \ - PATH="/opt/java/openjdk/bin:$PATH" - +FROM alpine:3.20.3 LABEL maintainer="WSO2 Docker Maintainers " +RUN apk update && apk upgrade --no-cache \ + && apk add --no-cache tzdata && apk upgrade libssl3 libcrypto3 + ENV LANG=C.UTF-8 ARG APK_USER=wso2 ARG APK_USER_ID=10001 +ARG CHECKSUM_AMD64="3ddaf85583613c97693e9b8aaa251dac07e73e366e159a7ccadbcf553117fcef" +ARG CHECKSUM_ARM64="5e17ff4c055f075b58a1cd7ec37843d989cd0072340222a4fd0730773382027e" ARG APK_USER_GROUP=wso2 ARG APK_USER_GROUP_ID=10001 ARG APK_USER_HOME=/home/${APK_USER} ARG GRPC_HEALTH_PROBE_PATH=/bin/grpc_health_probe ARG TARGETARCH -ARG APK_VERSION=1.0-SNAPSHOT -ENV VERSION=${APK_VERSION} -ENV JAVA_OPTS="" -ENV ENFORCER_HOME=${APK_USER_HOME} -ARG CHECKSUM_AMD64="3ddaf85583613c97693e9b8aaa251dac07e73e366e159a7ccadbcf553117fcef" -ARG CHECKSUM_ARM64="5e17ff4c055f075b58a1cd7ec37843d989cd0072340222a4fd0730773382027e" -ENV ENFORCER_PRIVATE_KEY_PATH=/home/wso2/security/keystore/mg.key -ENV ENFORCER_PUBLIC_CERT_PATH=/home/wso2/security/keystore/mg.pem -ENV TRUSTED_CA_CERTS_PATH=/home/wso2/security/truststore -ENV ADAPTER_HOST_NAME=adapter -ENV ADAPTER_HOST=adapter -ENV ADAPTER_XDS_PORT=18000 -ENV COMMON_CONTROLLER_HOST_NAME=common-controller -ENV COMMON_CONTROLLER_HOST=common-controller -ENV COMMON_CONTROLLER_XDS_PORT=18002 -ENV ENFORCER_LABEL="default" -ENV XDS_MAX_MSG_SIZE=4194304 -ENV XDS_MAX_RETRIES=3 -#todo update the connection string -ENV APPLICATIONINSIGHTS_CONNECTION_STRING=InstrumentationKey=;IngestionEndpoint=https://westus2-2.in.applicationinsights.azure.com/ ARG MOTD="\n\ Welcome to WSO2 Docker Resources \n\ --------------------------------- \n\ - This Docker container comprises of a WSO2 product, which is under the Apache License, Version 2.0. \n\ + This Docker container comprises of a WSO2 product, running with its latest GA release \n\ + which is under the Apache License, Version 2.0. \n\ Read more about Apache License, Version 2.0 here @ http://www.apache.org/licenses/LICENSE-2.0.\n" RUN \ - apt-get update && apt-get dist-upgrade -y && apt-get autoclean -y && apt-get autoremove -y -RUN \ - groupadd --system -g ${APK_USER_GROUP_ID} ${APK_USER_GROUP} \ - && useradd --system --create-home --home-dir ${APK_USER_HOME} --no-log-init -g ${APK_USER_GROUP} -u ${APK_USER_ID} ${APK_USER} \ - && mkdir ${APK_USER_HOME}/logs && mkdir -p ${APK_USER_HOME}/lib/dropins \ + addgroup -S -g ${APK_USER_GROUP_ID} ${APK_USER_GROUP} \ + && adduser -S -u ${APK_USER_ID} -h ${APK_USER_HOME} -G ${APK_USER_GROUP} ${APK_USER} \ + && mkdir ${APK_USER_HOME}/logs && mkdir -p ${APK_USER_HOME}/artifacts/apis \ && chown -R ${APK_USER}:${APK_USER_GROUP} ${APK_USER_HOME} \ && echo '[ ! -z "${TERM}" -a -r /etc/motd ] && cat /etc/motd' >> /etc/bash.bashrc; echo "${MOTD}" > /etc/motd RUN \ wget -q https://github.com/grpc-ecosystem/grpc-health-probe/releases/download/v0.4.34/grpc_health_probe-linux-${TARGETARCH} \ - && mv grpc_health_probe-linux-${TARGETARCH} ${GRPC_HEALTH_PROBE_PATH}\ + && mv grpc_health_probe-linux-${TARGETARCH} ${GRPC_HEALTH_PROBE_PATH} \ && if [ "${TARGETARCH}" = "amd64" ]; then echo "${CHECKSUM_AMD64} ${GRPC_HEALTH_PROBE_PATH}" | sha256sum -c -; fi - + RUN \ chmod +x ${GRPC_HEALTH_PROBE_PATH} \ && chown ${APK_USER}:${APK_USER_GROUP} ${GRPC_HEALTH_PROBE_PATH} \ @@ -118,13 +60,9 @@ RUN \ WORKDIR ${APK_USER_HOME} USER ${APK_USER_ID} -COPY resources/lib lib/ -COPY resources/conf/log4j2.properties conf/log4j2.properties -COPY resources/security security +COPY resources/conf/config.toml conf/ COPY resources/check_health.sh . +COPY resources/conf/log_config.toml conf/ +COPY ./${TARGETARCH}/main enforcer -#todo add applicationinsights.json file and point it to the appInsightsAgent jar -#Add the agent using JVM arg -javaagent:/home/wso2/conf/applicationinsights-agent-3.1.1.jar -#Add the config file using System property -Dapplicationinsights.configuration.file=/home/wso2/conf/applicationinsights.json - -CMD java -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath="${ENFORCER_HOME}/logs/heap-dump.hprof" $JAVA_OPTS -Dlog4j.configurationFile="${ENFORCER_HOME}/conf/log4j2.properties" -DtracingEnabled="true" -cp "lib/*:lib/dropins/*" org.wso2.apk.enforcer.server.AuthServer +CMD ./enforcer diff --git a/gateway/enforcer/build.gradle b/gateway/enforcer/build.gradle index f29997056a..b2c1d7066f 100644 --- a/gateway/enforcer/build.gradle +++ b/gateway/enforcer/build.gradle @@ -1,16 +1,16 @@ /* - * Copyright (c) 2022, WSO2 LLC. (https://www.wso2.com) All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); + * Copyright (c) 2024, WSO2 LLC. (https://www.wso2.com) All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and * limitations under the License. * */ @@ -18,36 +18,44 @@ plugins { id 'net.researchgate.release' version '2.8.0' } + apply from: "$rootDir/../../common-gradle-scripts/docker.gradle" -repositories { - mavenCentral() -} +apply from: "$rootDir/../../common-gradle-scripts/go.gradle" release { tagTemplate = 'enforcer-$version' git { requireBranch = project.hasProperty('releaseBranch') ? project.releaseBranch : 'main' - pushToRemote= "origin" } } -task build{ - dependsOn("resources:build") - finalizedBy docker_build -} - allprojects { group = project.group version = project.version } -subprojects { - apply from: "$rootDir/../../common-gradle-scripts/java.gradle" - afterReleaseBuild.dependsOn publish +tasks.register('go_test', Exec) { + group 'go' + description 'Automates testing the packages named by the import paths.' +} + +tasks.named('go_revive_run').configure { + finalizedBy go_tidy + // finalizedBy go_test +} + +tasks.named('go_build').configure { + dependsOn go_revive_run + dependsOn go_vet + println("Running go build") + finalizedBy docker_build } -tasks.named("afterReleaseBuild").configure { - dependsOn "docker_push" +task build{ + dependsOn go_build + dependsOn docker_build } + +afterReleaseBuild.dependsOn "docker_push" diff --git a/gateway/enforcer/cmd/enforcer/main.go b/gateway/enforcer/cmd/main.go similarity index 100% rename from gateway/enforcer/cmd/enforcer/main.go rename to gateway/enforcer/cmd/main.go diff --git a/gateway/enforcer/go.mod b/gateway/enforcer/go.mod index 4a48dd0333..9be8e16313 100644 --- a/gateway/enforcer/go.mod +++ b/gateway/enforcer/go.mod @@ -4,11 +4,13 @@ go 1.23.2 require ( github.com/envoyproxy/gateway v1.2.3 + github.com/envoyproxy/go-control-plane v0.13.1 github.com/go-logr/logr v1.4.2 github.com/go-logr/zapr v1.3.0 github.com/kelseyhightower/envconfig v1.4.0 github.com/stretchr/testify v1.10.0 - github.com/wso2/apk/adapter v0.0.0-00010101000000-000000000000 + github.com/wso2/apk/adapter v0.0.0-20231207051518-6dd728943082 + github.com/wso2/apk/common-go-libs v0.0.0-20241016075419-fc842057860d go.uber.org/zap v1.27.0 google.golang.org/grpc v1.67.1 ) @@ -16,7 +18,6 @@ require ( require ( github.com/cncf/xds/go v0.0.0-20240905190251-b4127c9b8d78 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect - github.com/envoyproxy/go-control-plane v0.13.1 // indirect github.com/envoyproxy/protoc-gen-validate v1.1.0 // indirect github.com/evanphx/json-patch v5.9.0+incompatible // indirect github.com/fxamacker/cbor/v2 v2.7.0 // indirect @@ -61,3 +62,5 @@ require ( replace github.com/wso2/apk/gateway/enforcer => ../enforcer replace github.com/wso2/apk/adapter => ../../adapter + +replace github.com/wso2/apk/common-go-libs => ../../common-go-libs diff --git a/gateway/enforcer/gradle.properties b/gateway/enforcer/gradle.properties index d8c5919911..0b2a0f3a6e 100644 --- a/gateway/enforcer/gradle.properties +++ b/gateway/enforcer/gradle.properties @@ -16,5 +16,6 @@ group=org.wso2.apk version=1.2.0-SNAPSHOT +file=cmd/main.go docker_image_name=apk-enforcer diff --git a/gateway/enforcer/internal/config/config.go b/gateway/enforcer/internal/config/config.go index 8a08d5b159..0b197994af 100644 --- a/gateway/enforcer/internal/config/config.go +++ b/gateway/enforcer/internal/config/config.go @@ -8,6 +8,7 @@ import ( "github.com/wso2/apk/gateway/enforcer/internal/logging" ) +// Server holds the configuration parameters for the application. type Server struct { TrustedAdapterCertsPath string `envconfig:"TRUSTED_CA_CERTS_PATH" default:"/home/wso2/security/truststore"` TrustDefaultCerts string `envconfig:"TRUST_DEFAULT_CERTS" default:"true"` @@ -25,22 +26,22 @@ type Server struct { CommonControllerXdsPort string `envconfig:"COMMON_CONTROLLER_XDS_PORT" default:"18002"` CommonControllerRestPort string `envconfig:"COMMON_CONTROLLER_REST_PORT" default:"18003"` XdsMaxMsgSize int `envconfig:"XDS_MAX_MSG_SIZE" default:"4194304"` - EnforcerRegionId string `envconfig:"ENFORCER_REGION" default:"UNKNOWN"` - XdsMaxRetries int `envconfig:"XDS_MAX_RETRIES" default:"3"` // Change to integer as needed + EnforcerRegionID string `envconfig:"ENFORCER_REGION" default:"UNKNOWN"` + XdsMaxRetries int `envconfig:"XDS_MAX_RETRIES" default:"3"` XdsRetryPeriod int `envconfig:"XDS_RETRY_PERIOD" default:"5000"` // milliseconds InstanceIdentifier string `envconfig:"HOSTNAME" default:"Unassigned"` RedisUsername string `envconfig:"REDIS_USERNAME" default:""` RedisPassword string `envconfig:"REDIS_PASSWORD" default:""` RedisHost string `envconfig:"REDIS_HOST" default:"redis-master"` RedisPort int `envconfig:"REDIS_PORT" default:"6379"` - IsRedisTlsEnabled bool `envconfig:"IS_REDIS_TLS_ENABLED" default:"false"` + IsRedisTLSEnabled bool `envconfig:"IS_REDIS_TLS_ENABLED" default:"false"` RevokedTokensRedisChannel string `envconfig:"REDIS_REVOKED_TOKENS_CHANNEL" default:"wso2-apk-revoked-tokens-channel"` RedisKeyFile string `envconfig:"REDIS_KEY_FILE" default:"/home/wso2/security/redis/redis.key"` RedisCertFile string `envconfig:"REDIS_CERT_FILE" default:"/home/wso2/security/redis/redis.crt"` RedisCaCertFile string `envconfig:"REDIS_CA_CERT_FILE" default:"/home/wso2/security/redis/ca.crt"` RevokedTokenCleanupInterval int `envconfig:"REVOKED_TOKEN_CLEANUP_INTERVAL" default:"3600"` // seconds ChoreoAnalyticsAuthToken string `envconfig:"CHOREO_ANALYTICS_AUTH_TOKEN" default:""` - ChoreoAnalyticsAuthUrl string `envconfig:"CHOREO_ANALYTICS_AUTH_URL" default:""` + ChoreoAnalyticsAuthURL string `envconfig:"CHOREO_ANALYTICS_AUTH_URL" default:""` MoesifToken string `envconfig:"MOESIF_TOKEN" default:""` LogLevel string `envconfig:"LOG_LEVEL" default:"INFO"` ExternalProcessingPort string `envconfig:"EXTERNAL_PROCESSING_PORT" default:"8080"` @@ -53,7 +54,7 @@ var ( settingInstance *Server ) -// GetSettings initializes and returns a singleton instance of the Settings struct. +// GetConfig initializes and returns a singleton instance of the Settings struct. // It uses sync.Once to ensure that the initialization logic is executed only once, // making it safe for concurrent use. If there is an error during the initialization, // the function will panic. diff --git a/gateway/enforcer/internal/ext_proc/ext_proc.go b/gateway/enforcer/internal/ext_proc/ext_proc.go index 454824d727..a5e6020fc1 100644 --- a/gateway/enforcer/internal/ext_proc/ext_proc.go +++ b/gateway/enforcer/internal/ext_proc/ext_proc.go @@ -1,4 +1,4 @@ -package ext_proc +package extproc import ( "io" @@ -12,10 +12,21 @@ import ( "google.golang.org/grpc/status" ) +// ExternalProcessingServer represents a server for handling external processing requests. +// It contains a logger for logging purposes. type ExternalProcessingServer struct { log logging.Logger } +// StartExternalProcessingServer initializes and starts the external processing server. +// It creates a gRPC server using the provided configuration and registers the external +// processor server with it. +// +// Parameters: +// - cfg: A pointer to the Server configuration which includes paths to the enforcer's +// public and private keys, and a logger instance. +// +// If there is an error during the creation of the gRPC server, the function will panic. func StartExternalProcessingServer(cfg *config.Server) { server, err := util.CreateGRPCServer(cfg.EnforcerPublicKeyPath, cfg.EnforcerPrivateKeyPath) if err != nil { @@ -24,6 +35,24 @@ func StartExternalProcessingServer(cfg *config.Server) { envoy_service_proc_v3.RegisterExternalProcessorServer(server, &ExternalProcessingServer{cfg.Logger}) } +// Process handles the external processing server stream. It continuously receives +// requests from the stream, processes them, and sends back appropriate responses. +// The function supports different types of processing requests including request headers, +// response headers, request body, and response body. +// +// Parameters: +// - srv: The stream server for processing external requests. +// +// Returns: +// - error: Returns an error if the context is done or if there is an issue receiving or sending the stream request. +// +// The function processes the following request types: +// - envoy_service_proc_v3.ProcessingRequest_RequestHeaders: Logs and processes request headers. +// - envoy_service_proc_v3.ProcessingRequest_ResponseHeaders: Logs and processes response headers. +// - envoy_service_proc_v3.ProcessingRequest_RequestBody: Logs and processes request body. +// - envoy_service_proc_v3.ProcessingRequest_ResponseBody: Logs and processes response body. +// +// If an unknown request type is received, it logs the unknown request type. func (s *ExternalProcessingServer) Process(srv envoy_service_proc_v3.ExternalProcessor_ProcessServer) error { ctx := srv.Context() for { diff --git a/gateway/enforcer/internal/logging/log.go b/gateway/enforcer/internal/logging/log.go index 175a1070ea..c03e071828 100644 --- a/gateway/enforcer/internal/logging/log.go +++ b/gateway/enforcer/internal/logging/log.go @@ -34,12 +34,22 @@ const ( TraceLevel = 2 ) +// Logger is a struct that embeds logr.Logger and provides additional logging capabilities. +// It includes a reference to EnvoyGatewayLogging configuration and a SugaredLogger for +// structured logging. +// +// Fields: +// - logging: A pointer to EnvoyGatewayLogging configuration. +// - sugaredLogger: A SugaredLogger instance for structured logging. type Logger struct { logr.Logger logging *egv1a1.EnvoyGatewayLogging sugaredLogger *zap.SugaredLogger } +// NewLogger creates a new Logger instance that logs to stdout. +// It uses the provided EnvoyGatewayLogging configuration and initializes +// the logger with the default log level for the Gateway component. func NewLogger(logging *egv1a1.EnvoyGatewayLogging) Logger { logger := initZapLogger(os.Stdout, logging, logging.Level[egv1a1.LogComponentGatewayDefault]) @@ -50,6 +60,9 @@ func NewLogger(logging *egv1a1.EnvoyGatewayLogging) Logger { } } +// FileLogger creates a Logger instance that logs to the specified file. +// The log level is configured using the provided level parameter. +// If the file cannot be opened, it panics. func FileLogger(file string, name string, level egv1a1.LogLevel) Logger { writer, err := os.OpenFile(file, os.O_WRONLY, 0o666) if err != nil { @@ -66,6 +79,8 @@ func FileLogger(file string, name string, level egv1a1.LogLevel) Logger { } } +// DefaultLogger creates a Logger instance with default logging settings. +// It logs to stdout and uses the specified log level for all components. func DefaultLogger(level egv1a1.LogLevel) Logger { logging := egv1a1.DefaultEnvoyGatewayLogging() logger := initZapLogger(os.Stdout, logging, level) @@ -100,7 +115,7 @@ func (l Logger) WithValues(keysAndValues ...interface{}) Logger { return l } -// A Sugar wraps the base Logger functionality in a slower, but less +// Sugar wraps the base Logger functionality in a slower, but less // verbose, API. Any Logger can be converted to a SugaredLogger with its Sugar // method. // @@ -140,12 +155,12 @@ func Debug(log logr.Logger, msg string) { log.V(DebugLevel).Info(msg) } -// Error logs an error level message using the provided logger. -// The log level is set to ErrorLevel and the message is logged with Info method. +// Info logs an informational message using the provided logger. +// The log level is set to InfoLevel and the message is logged with the Info method. // // Parameters: // log (logr.Logger): The logger instance to use for logging. -// msg (string): The error message to log. +// msg (string): The informational message to log. func Info(log logr.Logger, msg string) { log.V(InfoLevel).Info(msg) } \ No newline at end of file diff --git a/gateway/enforcer/internal/util/cert.go b/gateway/enforcer/internal/util/cert.go index b9fb7fba97..e74502556a 100644 --- a/gateway/enforcer/internal/util/cert.go +++ b/gateway/enforcer/internal/util/cert.go @@ -7,6 +7,8 @@ import ( "io/ioutil" ) +// LoadCertificates loads a client certificate and private key from the given file paths. +// It returns the loaded tls.Certificate and an error if any issues occur during loading. func LoadCertificates(publicKeyPath, privateKeyPath string) (tls.Certificate, error) { clientCert, err := tls.LoadX509KeyPair(publicKeyPath, privateKeyPath) if err != nil { @@ -15,6 +17,9 @@ func LoadCertificates(publicKeyPath, privateKeyPath string) (tls.Certificate, er return clientCert, nil } +// LoadCACertificates loads the CA certificates from the provided file path. +// It reads the certificate file and appends it to a new CertPool. +// If any error occurs during reading or appending, it returns an error. func LoadCACertificates(trustedCertsPath string) (*x509.CertPool, error) { caCert, err := ioutil.ReadFile(trustedCertsPath) if err != nil { @@ -29,6 +34,8 @@ func LoadCACertificates(trustedCertsPath string) (*x509.CertPool, error) { return certPool, nil } +// CreateTLSConfig creates and returns a new TLS configuration using the provided client certificate +// and CA certificate pool. It sets up the certificates for secure communication. func CreateTLSConfig(cert tls.Certificate, certPool *x509.CertPool) *tls.Config { return &tls.Config{ Certificates: []tls.Certificate{cert}, diff --git a/gateway/enforcer/internal/util/grpc.go b/gateway/enforcer/internal/util/grpc.go index 1c27a39c76..074096dff3 100644 --- a/gateway/enforcer/internal/util/grpc.go +++ b/gateway/enforcer/internal/util/grpc.go @@ -11,6 +11,9 @@ import ( "google.golang.org/grpc/keepalive" ) +// CreateGRPCConnection creates a gRPC connection using the provided context, host, port, and TLS configuration. +// It also sets up keepalive parameters for the connection to ensure that the connection remains alive even if no data is being sent. +// It returns a gRPC connection object and an error if the connection fails. func CreateGRPCConnection(ctx context.Context, host, port string, tlsConfig *tls.Config) (*grpc.ClientConn, error) { address := fmt.Sprintf("%s:%s", host, port) @@ -34,6 +37,9 @@ func CreateGRPCConnection(ctx context.Context, host, port string, tlsConfig *tls return conn, nil } +// CreateGRPCConnectionWithRetry attempts to create a gRPC connection with retry logic. +// If the connection fails, it retries based on the provided maxRetries and retryInterval. +// If successful, it returns the gRPC connection; otherwise, it returns an error. func CreateGRPCConnectionWithRetry(ctx context.Context, host, port string, tlsConfig *tls.Config, maxRetries int, retryInterval time.Duration) (*grpc.ClientConn, error) { for retries := 0; maxRetries == -1 || retries < maxRetries; retries++ { conn, err := CreateGRPCConnection(ctx, host, port, tlsConfig) @@ -45,6 +51,8 @@ func CreateGRPCConnectionWithRetry(ctx context.Context, host, port string, tlsCo return nil, fmt.Errorf("failed to create gRPC connection after %d retries", maxRetries) } +// CreateGRPCConnectionWithRetryAndPanic is similar to CreateGRPCConnectionWithRetry, but it panics if the connection cannot be established +// after the specified number of retries. It is typically used when the application cannot proceed without the connection. func CreateGRPCConnectionWithRetryAndPanic(ctx context.Context, host, port string, tlsConfig *tls.Config, maxRetries int, retryInterval time.Duration) *grpc.ClientConn { conn, err := CreateGRPCConnectionWithRetry(ctx, host, port, tlsConfig, maxRetries, retryInterval) if err != nil { @@ -53,6 +61,8 @@ func CreateGRPCConnectionWithRetryAndPanic(ctx context.Context, host, port strin return conn } +// CreateGRPCServer creates a new gRPC server using the provided public and private key paths to load the TLS credentials. +// It returns the created gRPC server or an error if the credentials cannot be loaded. func CreateGRPCServer(publicKeyPath, privateKeyPath string) (*grpc.Server, error) { // Load TLS credentials cert, err := LoadCertificates(publicKeyPath, privateKeyPath) diff --git a/gateway/enforcer/internal/xds/api_client.go b/gateway/enforcer/internal/xds/api_client.go index 0c8a74a1db..8a04591739 100644 --- a/gateway/enforcer/internal/xds/api_client.go +++ b/gateway/enforcer/internal/xds/api_client.go @@ -13,6 +13,8 @@ import ( "google.golang.org/grpc" ) +// APIXDSClient manages the connection to the API Discovery Service via gRPC. +// It supports connection retries, TLS configuration, and handling of API stream data. type APIXDSClient struct { Host string Port string @@ -26,6 +28,8 @@ type APIXDSClient struct { log logging.Logger } +// NewAPIXDSClient initializes a new instance of APIXDSClient with the given parameters. +// It sets up the host, port, retry logic, TLS configuration, and logger. func NewAPIXDSClient(host string, port string, maxRetries int, retryInterval time.Duration, tlsConfig *tls.Config, cfg *config.Server) *APIXDSClient { // Create a new APIClient object return &APIXDSClient{ @@ -39,6 +43,9 @@ func NewAPIXDSClient(host string, port string, maxRetries int, retryInterval tim } } +// InitiateAPIXDSConnection establishes a gRPC connection to the API Discovery Service +// and initiates a streaming API configuration. If the connection fails, it will retry +// based on the configured retry policy. Received configuration updates are logged. func (c *APIXDSClient) InitiateAPIXDSConnection() { grpcConn := util.CreateGRPCConnectionWithRetryAndPanic(nil, c.Host, c.Port, c.tlsConfig, c.maxRetries, c.retryInterval) c.grpcConn = grpcConn diff --git a/gateway/enforcer/internal/xds/client_manager.go b/gateway/enforcer/internal/xds/client_manager.go index 7adea7522a..280e80ba6b 100644 --- a/gateway/enforcer/internal/xds/client_manager.go +++ b/gateway/enforcer/internal/xds/client_manager.go @@ -6,6 +6,9 @@ import ( "time" ) +// CreateXDSClients initializes and establishes connections for multiple XDS clients, +// including API XDS, Config XDS, and JWT Issuer XDS clients. +// It handles TLS configuration, certificate loading, and connection setup. func CreateXDSClients(cfg *config.Server) { clientCert, err := util.LoadCertificates(cfg.EnforcerPublicKeyPath, cfg.EnforcerPrivateKeyPath) if err != nil { diff --git a/gateway/enforcer/internal/xds/config_client.go b/gateway/enforcer/internal/xds/config_client.go index dcd8fac323..11235a5f13 100644 --- a/gateway/enforcer/internal/xds/config_client.go +++ b/gateway/enforcer/internal/xds/config_client.go @@ -13,6 +13,8 @@ import ( "google.golang.org/grpc" ) +// ConfigXDSClient is a client for managing gRPC connections to the Config Discovery Service (XDS). +// It handles retry logic, TLS configuration, and logging for configuration data streams. type ConfigXDSClient struct { Host string Port string @@ -26,6 +28,8 @@ type ConfigXDSClient struct { log logging.Logger } +// NewXDSConfigClient creates a new instance of ConfigXDSClient. +// It initializes the client with the given host, port, retry parameters, TLS configuration, and logger. func NewXDSConfigClient(host string, port string, maxRetries int, retryInterval time.Duration, tlsConfig *tls.Config, cfg *config.Server) *ConfigXDSClient { // Create a new APIClient object return &ConfigXDSClient{ @@ -39,6 +43,8 @@ func NewXDSConfigClient(host string, port string, maxRetries int, retryInterval } } +// InitiateConfigXDSConnection establishes and maintains a gRPC connection to the Config Discovery Service. +// It also handles reconnection logic on errors and listens for incoming configuration streams. func (c *ConfigXDSClient) InitiateConfigXDSConnection() { grpcConn := util.CreateGRPCConnectionWithRetryAndPanic(nil, c.Host, c.Port, c.tlsConfig, c.maxRetries, c.retryInterval) c.grpcConn = grpcConn diff --git a/gateway/enforcer/internal/xds/jwt_issuer_client.go b/gateway/enforcer/internal/xds/jwt_issuer_client.go index e79a6b0e4c..04a909448a 100644 --- a/gateway/enforcer/internal/xds/jwt_issuer_client.go +++ b/gateway/enforcer/internal/xds/jwt_issuer_client.go @@ -13,6 +13,8 @@ import ( "google.golang.org/grpc" ) +// JWTIssuerXDSClient is a client for managing gRPC connections to the API Discovery Service (XDS) +// for JWT issuer-related configurations. It includes retry logic, TLS configuration, and logging. type JWTIssuerXDSClient struct { Host string Port string @@ -26,6 +28,8 @@ type JWTIssuerXDSClient struct { log logging.Logger } +// NewJWTIssuerXDSClient creates a new instance of JWTIssuerXDSClient. +// It initializes the client with the given host, port, retry parameters, TLS configuration, and logger. func NewJWTIssuerXDSClient(host string, port string, maxRetries int, retryInterval time.Duration, tlsConfig *tls.Config, cfg *config.Server) *JWTIssuerXDSClient { // Create a new APIClient object return &JWTIssuerXDSClient{ @@ -39,6 +43,8 @@ func NewJWTIssuerXDSClient(host string, port string, maxRetries int, retryInterv } } +// InitiateSubscriptionXDSConnection establishes and maintains a gRPC connection to the API Discovery Service. +// It also handles reconnection logic on errors and listens for incoming JWT issuer configuration streams. func (c *JWTIssuerXDSClient) InitiateSubscriptionXDSConnection() { grpcConn := util.CreateGRPCConnectionWithRetryAndPanic(nil, c.Host, c.Port, c.tlsConfig, c.maxRetries, c.retryInterval) c.grpcConn = grpcConn diff --git a/gateway/enforcer/resources/check_health.sh b/gateway/enforcer/resources/check_health.sh new file mode 100755 index 0000000000..8d5e18abd5 --- /dev/null +++ b/gateway/enforcer/resources/check_health.sh @@ -0,0 +1,26 @@ +#!/bin/bash +# -------------------------------------------------------------------- +# Copyright (c) 2023, WSO2 LLC. (http://wso2.com) All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ----------------------------------------------------------------------- + +ADAPTER_XDS_PORT="${ADAPTER_XDS_PORT:-18000}" +ADAPTER_SERVER_NAME="${ADAPTER_SERVER_NAME:-adapter}" +grpc_health_probe -addr "127.0.0.1:${ADAPTER_XDS_PORT}" \ + -tls \ + -tls-ca-cert "${ADAPTER_PUBLIC_CERT_PATH}" \ + -tls-client-cert "${ADAPTER_PUBLIC_CERT_PATH}" \ + -tls-client-key "${ADAPTER_PRIVATE_KEY_PATH}" \ + -tls-server-name ${ADAPTER_SERVER_NAME} \ + -connect-timeout=3s \ No newline at end of file diff --git a/gateway/enforcer/resources/conf/config.toml b/gateway/enforcer/resources/conf/config.toml new file mode 100644 index 0000000000..0f2ec8f933 --- /dev/null +++ b/gateway/enforcer/resources/conf/config.toml @@ -0,0 +1,71 @@ +[adapter] +[adapter.server] + enabled = true + port = "9843" + tokenPrivateKeyPath = "/home/wso2/security/keystore/mg.key" + [[adapter.server.users]] + username = "admin" + password = "$env{adapter_admin_pwd}" + +[adapter.keystore] + certPath = "/home/wso2/security/keystore/mg.pem" + keyPath = "/home/wso2/security/keystore/mg.key" + +[adapter.truststore] + location = "/home/wso2/security/truststore" + +[router] + systemHost = "localhost" + useRemoteAddress = false + +[router.keystore] + certPath = "/home/wso2/security/keystore/mg.pem" + keyPath = "/home/wso2/security/keystore/mg.key" + +[router.upstream] +[router.upstream.tls] + trustedCertPath = "/etc/ssl/certs/ca-certificates.crt" + verifyHostName = true + disableSslVerification = false + +[router.downstream] +[router.downstream.tls] +mtlsAPIsEnabled = false +trustedCertPath = "/etc/ssl/certs/ca-certificates.crt" + +[enforcer.security] +[[enforcer.security.tokenService]] + name = "Resident Key Manager" + issuer = "https://localhost:9443/oauth2/token" + certificateAlias = "wso2carbon" + jwksURL = "" + validateSubscription = false + consumerKeyClaim = "azp" + certificateFilePath = "/home/wso2/security/truststore/wso2carbon.pem" + + +[[enforcer.security.tokenService]] + name = "APIM Publisher" + issuer = "https://localhost:9443/publisher" + validateSubscription = true + certificateFilePath = "/home/wso2/security/truststore/wso2carbon.pem" + +[enforcer.throttling] + enableGlobalEventPublishing = false + jmsConnectionProviderURL = "amqp://admin:$env{tm_admin_pwd}@carbon/carbon?brokerlist='tcp://apim:5672'" + [enforcer.throttling.publisher] + username = "admin" + password = "$env{tm_admin_pwd}" + [[enforcer.throttling.publisher.URLGroup]] + receiverURLs = ["tcp://apim:9611"] + authURLs = ["ssl://apim:9711"] + +[analytics] + enabled = false + +[enforcer.metrics] + enabled = false + +[managementServer] + serviceURL="localhost:18000" + NodeLabel="default" diff --git a/gateway/enforcer/resources/conf/log_config.toml b/gateway/enforcer/resources/conf/log_config.toml new file mode 100644 index 0000000000..9519d2eff2 --- /dev/null +++ b/gateway/enforcer/resources/conf/log_config.toml @@ -0,0 +1,37 @@ +# The logging configuration for Adapter + +## Adapter root Level configurations + +logLevel = "INFO" # LogLevels can be "DEBG", "FATL", "ERRO", "WARN", "INFO", "PANC" +LogFormat = "TEXT" # Values can be "JSON", "TEXT" + +[rotation] +MaxSize = 10 # In MegaBytes (MB) +MaxBackups = 3 +MaxAge = 2 # In days +Compress = true + +## Adapter package Level configurations + +[[pkg]] +name = "github.com/wso2/apk/adapter/internal/adapter" +logLevel = "INFO" # LogLevels can be "DEBG", "FATL", "ERRO", "WARN", "INFO", "PANC" + +[[pkg]] +name = "github.com/wso2/apk/adapter/internal/oasparser" +logLevel = "INFO" + + +# The logging configuration for Router + +[accessLogs] +enable = false +format = "[%START_TIME%] '%REQ(:METHOD)% %DYNAMIC_METADATA(envoy.filters.http.ext_authz:originalPath)% %REQ(:PATH)% %PROTOCOL%' %RESPONSE_CODE% %RESPONSE_FLAGS% %BYTES_RECEIVED% %BYTES_SENT% %DURATION% %RESP(X-ENVOY-UPSTREAM-SERVICE-TIME)% '%REQ(X-FORWARDED-FOR)%' '%REQ(USER-AGENT)%' '%REQ(X-REQUEST-ID)%' '%REQ(:AUTHORITY)%' '%UPSTREAM_HOST%'\n" + +[wireLogs] +enable = false +include = ["Headers", "Body", "Trailers"] + +# [[pkg]] +# name = "github.com/wso2/apk/Adapter/pkg/xds" +# logLevel = "INFO" diff --git a/gateway/enforcer/resources/test-resources/testcrt.crt b/gateway/enforcer/resources/test-resources/testcrt.crt new file mode 100644 index 0000000000..baf74db793 --- /dev/null +++ b/gateway/enforcer/resources/test-resources/testcrt.crt @@ -0,0 +1,44 @@ +-----BEGIN CERTIFICATE----- +MIIH0zCCBbugAwIBAgIIXsO3pkN/pOAwDQYJKoZIhvcNAQEFBQAwQjESMBAGA1UE +AwwJQUNDVlJBSVoxMRAwDgYDVQQLDAdQS0lBQ0NWMQ0wCwYDVQQKDARBQ0NWMQsw +CQYDVQQGEwJFUzAeFw0xMTA1MDUwOTM3MzdaFw0zMDEyMzEwOTM3MzdaMEIxEjAQ +BgNVBAMMCUFDQ1ZSQUlaMTEQMA4GA1UECwwHUEtJQUNDVjENMAsGA1UECgwEQUND +VjELMAkGA1UEBhMCRVMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCb +qau/YUqXry+XZpp0X9DZlv3P4uRm7x8fRzPCRKPfmt4ftVTdFXxpNRFvu8gMjmoY +HtiP2Ra8EEg2XPBjs5BaXCQ316PWywlxufEBcoSwfdtNgM3802/J+Nq2DoLSRYWo +G2ioPej0RGy9ocLLA76MPhMAhN9KSMDjIgro6TenGEyxCQ0jVn8ETdkXhBilyNpA +lHPrzg5XPAOBOp0KoVdDaaxXbXmQeOW1tDvYvEyNKKGno6e6Ak4l0Squ7a4DIrhr +IA8wKFSVf+DuzgpmndFALW4ir50awQUZ0m/A8p/4e7MCQvtQqR0tkw8jq8bBD5L/ +0KIV9VMJcRz/RROE5iZe+OCIHAr8Fraocwa48GOEAqDGWuzndN9wrqODJerWx5eH +k6fGioozl2A3ED6XPm4pFdahD9GILBKfb6qkxkLrQaLjlUPTAYVtjrs78yM2x/47 +4KElB0iryYl0/wiPgL/AlmXz7uxLaL2diMMxs0Dx6M/2OLuc5NF/1OVYm3z61PMO +m3WR5LpSLhl+0fXNWhn8ugb2+1KoS5kE3fj5tItQo05iifCHJPqDQsGH+tUtKSpa +cXpkatcnYGMN285J9Y0fkIkyF/hzQ7jSWpOGYdbhdQrqeWZ2iE9x6wQl1gpaepPl +uUsXQA+xtrn13k/c4LOsOxFwYIRKQ26ZIMApcQrAZQIDAQABo4ICyzCCAscwfQYI +KwYBBQUHAQEEcTBvMEwGCCsGAQUFBzAChkBodHRwOi8vd3d3LmFjY3YuZXMvZmls +ZWFkbWluL0FyY2hpdm9zL2NlcnRpZmljYWRvcy9yYWl6YWNjdjEuY3J0MB8GCCsG +AQUFBzABhhNodHRwOi8vb2NzcC5hY2N2LmVzMB0GA1UdDgQWBBTSh7Tj3zcnk1X2 +VuqB5TbMjB4/vTAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFNKHtOPfNyeT +VfZW6oHlNsyMHj+9MIIBcwYDVR0gBIIBajCCAWYwggFiBgRVHSAAMIIBWDCCASIG +CCsGAQUFBwICMIIBFB6CARAAQQB1AHQAbwByAGkAZABhAGQAIABkAGUAIABDAGUA +cgB0AGkAZgBpAGMAYQBjAGkA8wBuACAAUgBhAO0AegAgAGQAZQAgAGwAYQAgAEEA +QwBDAFYAIAAoAEEAZwBlAG4AYwBpAGEAIABkAGUAIABUAGUAYwBuAG8AbABvAGcA +7QBhACAAeQAgAEMAZQByAHQAaQBmAGkAYwBhAGMAaQDzAG4AIABFAGwAZQBjAHQA +cgDzAG4AaQBjAGEALAAgAEMASQBGACAAUQA0ADYAMAAxADEANQA2AEUAKQAuACAA +QwBQAFMAIABlAG4AIABoAHQAdABwADoALwAvAHcAdwB3AC4AYQBjAGMAdgAuAGUA +czAwBggrBgEFBQcCARYkaHR0cDovL3d3dy5hY2N2LmVzL2xlZ2lzbGFjaW9uX2Mu +aHRtMFUGA1UdHwROMEwwSqBIoEaGRGh0dHA6Ly93d3cuYWNjdi5lcy9maWxlYWRt +aW4vQXJjaGl2b3MvY2VydGlmaWNhZG9zL3JhaXphY2N2MV9kZXIuY3JsMA4GA1Ud +DwEB/wQEAwIBBjAXBgNVHREEEDAOgQxhY2N2QGFjY3YuZXMwDQYJKoZIhvcNAQEF +BQADggIBAJcxAp/n/UNnSEQU5CmH7UwoZtCPNdpNYbdKl02125DgBS4OxnnQ8pdp +D70ER9m+27Up2pvZrqmZ1dM8MJP1jaGo/AaNRPTKFpV8M9xii6g3+CfYCS0b78gU +JyCpZET/LtZ1qmxNYEAZSUNUY9rizLpm5U9EelvZaoErQNV/+QEnWCzI7UiRfD+m +AM/EKXMRNt6GGT6d7hmKG9Ww7Y49nCrADdg9ZuM8Db3VlFzi4qc1GwQA9j9ajepD +vV+JHanBsMyZ4k0ACtrJJ1vnE5Bc5PUzolVt3OAJTS+xJlsndQAJxGJ3KQhfnlms +tn6tn1QwIgPBHnFk/vk4CpYY3QIUrCPLBhwepH2NDd4nQeit2hW3sCPdK6jT2iWH +7ehVRE2I9DZ+hJp4rPcOVkkO1jMl1oRQQmwgEh0q1b688nCBpHBgvgW1m54ERL5h +I6zppSSMEYCUWqKiuUnSwdzRp+0xESyeGabu4VXhwOrPDYTkF7eifKXeVSUG7szA +h1xA2syVP1XgNce4hL60Xc16gwFy7ofmXx2utYXGJt/mwZrpHgJHnyqobalbz+xF +d3+YJ5oyXSrjhO7FmGYvliAd3djDJ9ew+f7Zfc3Qn48LFFhRny+Lwzgt3uiP1o2H +pPVWQxaZLPSkVrQ0uGE3ycJYgBugl6H8WY3pEfbRD0tVNEYqi4Y7 +-----END CERTIFICATE----- diff --git a/gateway/enforcer/revive.toml b/gateway/enforcer/revive.toml new file mode 100644 index 0000000000..7319491817 --- /dev/null +++ b/gateway/enforcer/revive.toml @@ -0,0 +1,28 @@ +ignoreGeneratedHeader = false +severity = "warning" +confidence = 0.8 +errorCode = 0 +warningCode = 0 + +[rule.blank-imports] +[rule.context-as-argument] +[rule.context-keys-type] +[rule.dot-imports] +[rule.error-return] +[rule.error-strings] +[rule.error-naming] +[rule.exported] +[rule.if-return] +[rule.increment-decrement] +[rule.var-naming] +[rule.var-declaration] +[rule.range] +[rule.receiver-naming] +[rule.time-naming] +[rule.unexported-return] +[rule.indent-error-flow] +[rule.errorf] +[rule.empty-block] +[rule.superfluous-else] +[rule.unreachable-code] +[rule.redefines-builtin-id]