Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ISSUE-680 Fix OAuth Client Secret env variable #1

Draft
wants to merge 14 commits into
base: master
Choose a base branch
from
Draft
7 changes: 5 additions & 2 deletions charts/pega/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -866,10 +866,12 @@ To configure authorization for the connection between Pega Infinity and the Sear
| Parameter | Description | Default value |
|-----------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|--------------------|
| `enabled` | Set the `pegasearch.srsAuth.enabled` to 'true' to use OAuth between Infinity and SRS. | false |
| `url` | Set the `pegasearch.srsAuth.url` value to the URL of the OAuth service endpoint to get the token for SRS. | `""` |
| `url` | Set the `pegasearch.srsAuth.url` value to the URL of the OAuth token endpoint to get the token for SRS. | `""` |
| `clientId` | Set the `pegasearch.srsAuth.clientId` value to the client id used in OAuth service. | `""` |
| `scopes` | Set the `pegasearch.srsAuth.scopes` value to "pega.search:full", the scope set in the OAuth service required to grant access to SRS. | "pega.search:full" |
| `privateKey` | Set the `pegasearch.srsAuth,privateKey` value to the OAuth private PKCS8 key (additionally encoded with base64) used to get an authorization token for the connection between Pega tiers and SRS. | `""` |
| `authType` | Set the `pegasearch.srsAuth.authType` value to to authentication type use when connecting to the OAuth token endpoint. Use client_secret_basic for basic authentication or private_key_jwt to use a client assertion JWT. | `""` |
| `external_secret_name`| Set the `pegasearch.srsAuth.external_secret_name` value to the secret that contains the OAuth private PKCS8 key (additionally encoded with base64) used to get an authorization token for the connection between Pega tiers and SRS. The private key should be contained in the secret key SRS_OAUTH_PRIVATE_KEY. | `""` |
| `privateKey` | When not using an external secret, set the `pegasearch.srsAuth.privateKey` value to the OAuth private PKCS8 key (additionally encoded with base64) used to get an authorization token for the connection between Pega tiers and SRS. | `""` |
| `privateKeyAlgorithm` | Set the `pegasearch.srsAuth.privateKeyAlgorithm` value to the algorithm used to generate a private key used by the OAuth client. Allowed values: RS256 (default), RS384, RS512, ES256, ES384, ES512. | "RS256" |

Example:
Expand All @@ -882,6 +884,7 @@ pegasearch:
enabled: true
url: "https:/your-authorization-service-host/oauth2/v1/token"
clientId: "your-client-id"
authType: client_secret_basic
scopes: "pega.search:full"
privateKey: "LS0tLS1CRUdJTiBSU0Eg...<truncated>"
privateKeyAlgorithm: "RS256"
Expand Down
12 changes: 11 additions & 1 deletion charts/pega/templates/_helpers.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -375,11 +375,21 @@ dnsConfig:
{{- if (.Values.pegasearch.srsAuth).privateKey }}
{{- .Values.pegasearch.srsAuth.privateKey | b64enc }}
{{- else }}
{{- fail "A valid entry is required for pegasearch.srsAuth.privateKey, when request authentication mechanism(IDP) is enabled between SRS and Pega Infinity i.e. pegasearch.srsAuth.enabled is true." | quote}}
{{- fail "A valid entry is required for pegasearch.srsAuth.privateKey or pegasearch.srsAuth.external_secret_name, when request authentication mechanism(IDP) is enabled between SRS and Pega Infinity i.e. pegasearch.srsAuth.enabled is true." | quote }}
{{- end }}
{{- end }}
{{- end }}

{{- define "srsAuthEnvSecretFrom" }}
{{- if .Values.pegasearch.srsAuth.external_secret_name }}
name: {{ .Values.pegasearch.srsAuth.external_secret_name }}
key: SRS_OAUTH_PRIVATE_KEY
{{- else }}
name: pega-srs-auth-secret
key: privateKey
{{- end }}
{{- end }}

{{- define "ingressApiVersion" }}
{{- if (semverCompare ">= 1.19.0-0" (trimPrefix "v" .root.Capabilities.KubeVersion.GitVersion)) }}
apiVersion: networking.k8s.io/v1
Expand Down
12 changes: 10 additions & 2 deletions charts/pega/templates/_pega-deployment.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -203,11 +203,19 @@ spec:
- name: MAX_RETRIES
value: {{ include "tierClassloaderMaxRetries" (dict "failureThreshold" $livenessProbeFailureThreshold "periodSeconds" $livenessProbePeriodSeconds ) | quote }}
{{- if and (.root.Values.pegasearch.externalSearchService) ((.root.Values.pegasearch.srsAuth).enabled) }}
{{- if or (not .root.Values.pegasearch.srsAuth.authType) (eq .root.Values.pegasearch.srsAuth.authType "private_key_jwt") }}
- name: SERV_AUTH_PRIVATE_KEY
valueFrom:
secretKeyRef:
name: pega-srs-auth-secret
key: privateKey
{{- include "srsAuthEnvSecretFrom" .root | indent 14 }}
{{- else if eq .root.Values.pegasearch.srsAuth.authType "client_secret_basic" }}
- name: SERV_AUTH_CLIENT_SECRET
valueFrom:
secretKeyRef:
{{- include "srsAuthEnvSecretFrom" .root | indent 14 }}
{{- else }}
{{- fail "pegasearch.srsAuth.authType must be either private_key_jwt or client_secret_basic." }}
{{- end }}
{{- end }}
envFrom:
- configMapRef:
Expand Down
2 changes: 1 addition & 1 deletion charts/pega/templates/pega-srs-auth-secret.yaml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{{- if and (.Values.pegasearch.externalSearchService) ((.Values.pegasearch.srsAuth).enabled) }}
{{- if and (.Values.pegasearch.externalSearchService) ((.Values.pegasearch.srsAuth).enabled) (not .Values.pegasearch.srsAuth.external_secret_name) }}
# Secret for OAuth private key used to get an authorization token for Pega Infinity connection to Search and Reporting Service
apiVersion: v1
kind: Secret
Expand Down
13 changes: 12 additions & 1 deletion charts/pega/values-large.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -415,11 +415,22 @@ dds:
# Elasticsearch deployment settings.
# Note: This Elasticsearch deployment is used for Pega search, and is not the same Elasticsearch deployment used by the EFK stack.
# These search nodes will be deployed regardless of the Elasticsearch configuration above.
# Refer to README document to configure `Search and Reporting Service` as a search functionality provider under this section.
pegasearch:
image: "pegasystems/search"
memLimit: "3Gi"

# Set externalSearchService to true to use the Search and Reporting Service.
# Refer to the README document to configure SRS as a search functionality provider under this section.
externalSearchService: false
externalURL:
srsAuth:
enabled: false
url: ""
clientId: ""
authType: ""
privateKey: ""
external_secret_name: ""

# Pega Installer settings
installer:
image: "YOUR_INSTALLER_IMAGE:TAG"
Expand Down
13 changes: 12 additions & 1 deletion charts/pega/values-minimal.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -208,11 +208,22 @@ dds:
# Elasticsearch deployment settings.
# Note: This Elasticsearch deployment is used for Pega search, and is not the same Elasticsearch deployment used by the EFK stack.
# These search nodes will be deployed regardless of the Elasticsearch configuration above.
# Refer to README document to configure `Search and Reporting Service` as a search functionality provider under this section.
pegasearch:
image: "pegasystems/search"
memLimit: "3Gi"

# Set externalSearchService to true to use the Search and Reporting Service.
# Refer to the README document to configure SRS as a search functionality provider under this section.
externalSearchService: false
externalURL:
srsAuth:
enabled: false
url: ""
clientId: ""
authType: ""
privateKey: ""
external_secret_name: ""

# Pega Installer settings
installer:
image: "YOUR_INSTALLER_IMAGE:TAG"
Expand Down
13 changes: 12 additions & 1 deletion charts/pega/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -476,12 +476,23 @@ dds:
# Elasticsearch deployment settings.
# Note: This Elasticsearch deployment is used for Pega search, and is not the same Elasticsearch deployment used by the EFK stack.
# These search nodes will be deployed regardless of the Elasticsearch configuration above.
# Refer to README document to configure `Search and Reporting Service` as a search functionality provider under this section.
pegasearch:
image: "pegasystems/search"
memLimit: "3Gi"
replicas: 1

# Set externalSearchService to true to use the Search and Reporting Service.
# Refer to the README document to configure SRS as a search functionality provider under this section.
externalSearchService: false
externalURL:
srsAuth:
enabled: false
url: ""
clientId: ""
authType: ""
privateKey: ""
external_secret_name: ""

# Pega Installer settings.
installer:
image: "YOUR_INSTALLER_IMAGE:TAG"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import (
)

func TestPegaDeploymentWithSRSDisabled(t *testing.T) {
var supportedVendors = []string{"k8s", "eks", "gke", "aks"}
var supportedVendors = []string{"k8s", "eks", "gke", "aks", "pks", "openshift"}
var supportedOperations = []string{"deploy", "install-deploy"}

helmChartPath, err := filepath.Abs(PegaHelmChartPath)
Expand All @@ -35,7 +35,7 @@ func TestPegaDeploymentWithSRSDisabled(t *testing.T) {
}

func TestPegaDeploymentWithSRSAuthDisabled(t *testing.T) {
var supportedVendors = []string{"k8s", "eks", "gke", "aks"}
var supportedVendors = []string{"k8s", "eks", "gke", "aks", "pks", "openshift"}
var supportedOperations = []string{"deploy", "install-deploy"}

helmChartPath, err := filepath.Abs(PegaHelmChartPath)
Expand All @@ -61,28 +61,35 @@ func TestPegaDeploymentWithSRSAuthDisabled(t *testing.T) {
}

func TestPegaDeploymentWithSRSAuthEnabled(t *testing.T) {
var supportedVendors = []string{"k8s", "eks", "gke", "aks"}
var supportedVendors = []string{"k8s", "eks", "gke", "aks", "pks", "openshift"}
var supportedOperations = []string{"deploy", "install-deploy"}
var supportedSrsAuthTypes = []string{"", "private_key_jwt", "client_secret_basic"}
var supportedExternalSecrets = []string{"", "test-external-secret"}

helmChartPath, err := filepath.Abs(PegaHelmChartPath)
require.NoError(t, err)

for _, vendor := range supportedVendors {
for _, operation := range supportedOperations {

var options = &helm.Options{
SetValues: map[string]string{
"global.provider": vendor,
"global.actions.execute": operation,
"pegasearch.externalSearchService": "true",
"pegasearch.srsAuth.enabled": "true",
"pegasearch.srsAuth.privateKey": SRSAuthPrivateKeyExample,
},
}
deploymentYaml := RenderTemplate(t, options, helmChartPath, []string{"templates/pega-tier-deployment.yaml"})
deployments := strings.Split(deploymentYaml, "---")
for _, deployment := range deployments {
assertHasSRSAuthSettings(t, deployment)
for _, authType := range supportedSrsAuthTypes {
for _, externalSecret := range supportedExternalSecrets {
var options = &helm.Options{
SetValues: map[string]string{
"global.provider": vendor,
"global.actions.execute": operation,
"pegasearch.externalSearchService": "true",
"pegasearch.srsAuth.enabled": "true",
"pegasearch.srsAuth.privateKey": SRSAuthPrivateKeyExample,
"pegasearch.srsAuth.authType": authType,
"pegasearch.srsAuth.external_secret_name": externalSecret,
},
}
deploymentYaml := RenderTemplate(t, options, helmChartPath, []string{"templates/pega-tier-deployment.yaml"})
deployments := strings.Split(deploymentYaml, "---")
for _, deployment := range deployments {
assertHasSRSAuthSettings(t, deployment, authType, externalSecret)
}
}
}
}
}
Expand All @@ -96,22 +103,49 @@ func assertNoSRSAuthSettings(t *testing.T, pegaTierDeployment string) {
if "SERV_AUTH_PRIVATE_KEY" == envVar.Name {
require.Fail(t, "container '"+container.Name+"' should not have 'SERV_AUTH_PRIVATE_KEY' environment variable")
}
if "SERV_AUTH_CLIENT_SECRET" == envVar.Name {
require.Fail(t, "container '"+container.Name+"' should not have 'SERV_AUTH_CLIENT_SECRET' environment variable")
}
}
}
}

func assertHasSRSAuthSettings(t *testing.T, pegaTierDeployment string) {
func assertHasSRSAuthSettings(t *testing.T, pegaTierDeployment string, authType string, externalSecret string) {
var deployment appsv1.Deployment
UnmarshalK8SYaml(t, pegaTierDeployment, &deployment)
for _, container := range deployment.Spec.Template.Spec.Containers {
hasPrivateKey := false
hasClientPrivateKey := false
for _, envVar := range container.Env {
if "SERV_AUTH_PRIVATE_KEY" == envVar.Name {
require.Equal(t, "pega-srs-auth-secret", envVar.ValueFrom.SecretKeyRef.Name)
require.Equal(t, "privateKey", envVar.ValueFrom.SecretKeyRef.Key)
if externalSecret == "" {
require.Equal(t, "pega-srs-auth-secret", envVar.ValueFrom.SecretKeyRef.Name)
require.Equal(t, "privateKey", envVar.ValueFrom.SecretKeyRef.Key)
} else {
require.Equal(t, externalSecret, envVar.ValueFrom.SecretKeyRef.Name)
require.Equal(t, "SRS_OAUTH_PRIVATE_KEY", envVar.ValueFrom.SecretKeyRef.Key)
}
hasPrivateKey = true
}
if "SERV_AUTH_CLIENT_SECRET" == envVar.Name {
if externalSecret == "" {
require.Equal(t, "pega-srs-auth-secret", envVar.ValueFrom.SecretKeyRef.Name)
require.Equal(t, "privateKey", envVar.ValueFrom.SecretKeyRef.Key)
} else {
require.Equal(t, externalSecret, envVar.ValueFrom.SecretKeyRef.Name)
require.Equal(t, "SRS_OAUTH_PRIVATE_KEY", envVar.ValueFrom.SecretKeyRef.Key)
}
hasClientPrivateKey = true
}
}
if authType == "private_key_jwt" || authType == "" {
require.True(t, hasPrivateKey, "container '"+container.Name+"' should have 'SERV_AUTH_PRIVATE_KEY' environment variable")
require.False(t, hasClientPrivateKey, "container '"+container.Name+"' should not have 'SERV_AUTH_CLIENT_SECRET' environment variable")
}

if authType == "client_secret_basic" {
require.True(t, hasClientPrivateKey, "container '"+container.Name+"' should have 'SERV_AUTH_CLIENT_SECRET' environment variable")
require.False(t, hasPrivateKey, "container '"+container.Name+"' should not have 'SERV_AUTH_PRIVATE_KEY' environment variable")
}
require.True(t, hasPrivateKey, "container '"+container.Name+"' should have 'SERV_AUTH_PRIVATE_KEY' environment variable")
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,7 @@ func VerifyPegaWithoutExternalSRSEnvironmentConfig(t *testing.T, yamlContent str
}

func VerifyEnvConfigDataWithoutAuthVariables(t *testing.T, envConfigData map[string]string) {
authEnvironmentVariables := []string{"SERV_AUTH_URL", "SERV_AUTH_CLIENT_ID", "SERV_AUTH_SCOPES", "SERV_AUTH_PRIVATE_KEY_ALGORITHM", "SERV_AUTH_PRIVATE_KEY"}
authEnvironmentVariables := []string{"SERV_AUTH_URL", "SERV_AUTH_CLIENT_ID", "SERV_AUTH_SCOPES", "SERV_AUTH_PRIVATE_KEY_ALGORITHM", "SERV_AUTH_PRIVAYE_KEY", "SERV_AUTH_CLIENT_SECRET"}
for _, authEnvironmentVariable := range authEnvironmentVariables {
require.Emptyf(t, envConfigData[authEnvironmentVariable], "Environment variable '%s' should be empty", authEnvironmentVariable)
}
Expand All @@ -203,4 +203,6 @@ func VerifyEnvConfigDataWithAuthVariables(t *testing.T, envConfigData map[string
require.Equal(t, expectedAlgorithm, envConfigData["SERV_AUTH_PRIVATE_KEY_ALGORITHM"])
_, hasPrivateKey := envConfigData["SERV_AUTH_PRIVATE_KEY"]
require.False(t, hasPrivateKey)
_, hasClientPrivateKey := envConfigData["SERV_AUTH_CLIENT_SECRET"]
require.False(t, hasClientPrivateKey)
}
34 changes: 32 additions & 2 deletions terratest/src/test/pega/pega-srs-auth-secret_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,8 +89,38 @@ func TestPegaSRSAuthSecretNotCreatedForMissingPrivateKey(t *testing.T) {
}

yamlContent, err := RenderTemplateE(t, options, helmChartPath, []string{"templates/pega-srs-auth-secret.yaml"})
require.Contains(t, yamlContent, "A valid entry is required for pegasearch.srsAuth.privateKey, when request authentication mechanism(IDP) is enabled between SRS and Pega Infinity i.e. pegasearch.srsAuth.enabled is true")
require.Contains(t, err.Error(), "A valid entry is required for pegasearch.srsAuth.privateKey, when request authentication mechanism(IDP) is enabled between SRS and Pega Infinity i.e. pegasearch.srsAuth.enabled is true")
require.Contains(t, yamlContent, "A valid entry is required for pegasearch.srsAuth.privateKey or pegasearch.srsAuth.external_secret_name, when request authentication mechanism(IDP) is enabled between SRS and Pega Infinity i.e. pegasearch.srsAuth.enabled is true.")
require.Contains(t, err.Error(), "A valid entry is required for pegasearch.srsAuth.privateKey or pegasearch.srsAuth.external_secret_name, when request authentication mechanism(IDP) is enabled between SRS and Pega Infinity i.e. pegasearch.srsAuth.enabled is true.")
}
}
}
}

func TestPegaSRSAuthSecretNotCreatedForDeploymentWithEnabledSRSAuthAndExternalSecret(t *testing.T) {
var supportedVendors = []string{"k8s", "openshift", "eks", "gke", "aks", "pks"}
var supportedOperations = []string{"install", "install-deploy"}
var deploymentNames = []string{"pega", "myapp-dev"}

helmChartPath, err := filepath.Abs(PegaHelmChartPath)
require.NoError(t, err)

for _, vendor := range supportedVendors {
for _, operation := range supportedOperations {
for _, depName := range deploymentNames {
fmt.Println(vendor + "-" + operation + "-" + depName)

var options = &helm.Options{
SetValues: map[string]string{
"global.deployment.name": depName,
"global.provider": vendor,
"pegasearch.externalSearchService": "true",
"pegasearch.srsAuth.enabled": "true",
"pegasearch.srsAuth.external_secret_name": "test-external-secret",
},
}

yamlContent, err := RenderTemplateE(t, options, helmChartPath, []string{"templates/pega-srs-auth-secret.yaml"})
VerifySRSAuthSecretIsNotCreated(t, yamlContent, err)
}
}
}
Expand Down
Loading