Skip to content

Commit

Permalink
Provide uaa.yml via ConfigMap in k8s
Browse files Browse the repository at this point in the history
rather than having it be on the classpath of the compiled artifact.

[#169718758]

Signed-off-by: Andrew Edstrom <[email protected]>
Signed-off-by: Andrew Wittrock <[email protected]>
  • Loading branch information
andrewedstrom authored and Birdrock committed Jan 22, 2020
1 parent 46b4b94 commit 5391b93
Show file tree
Hide file tree
Showing 13 changed files with 311 additions and 7 deletions.
1 change: 1 addition & 0 deletions k8s/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,6 @@ format:
test:
go test -count=1 ./...

.PHONY: render
render:
@ytt -f templates
1 change: 1 addition & 0 deletions k8s/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ go 1.13
require (
github.com/onsi/ginkgo v1.11.0
github.com/onsi/gomega v1.8.1
gopkg.in/yaml.v2 v2.2.4
k8s.io/api v0.17.1
k8s.io/client-go v11.0.0+incompatible
)
10 changes: 10 additions & 0 deletions k8s/templates/config.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#@ load("@ytt:yaml", "yaml")
#@ load("uaa.lib.yml", "config")
---
apiVersion: v1
kind: ConfigMap
metadata:
name: uaa-config
data:
uaa.yml: #@ yaml.encode(config())

13 changes: 10 additions & 3 deletions k8s/templates/deployment.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,14 @@ spec:
- containerPort: 8080
protocol: TCP
env:
- name: LOGIN_CONFIG_URL
value: "classpath:required_configuration.yml"
- name: spring_profiles
value: "default,hsqldb"
value: "default,hsqldb"
- name: UAA_CONFIG_PATH
value: /etc/config
volumeMounts:
- name: uaa-config
mountPath: /etc/config
volumes:
- name: uaa-config
configMap:
name: uaa-config
69 changes: 69 additions & 0 deletions k8s/templates/uaa.lib.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
#@ load("@ytt:data", "data")
#@ def config():
---
issuer:
uri: http://localhost:8080/uaa

encryption:
active_key_label: CHANGE-THIS-KEY
encryption_keys:
- label: CHANGE-THIS-KEY
passphrase: CHANGEME

login:
serviceProviderKey: |
-----BEGIN RSA PRIVATE KEY-----
MIICXQIBAAKBgQDHtC5gUXxBKpEqZTLkNvFwNGnNIkggNOwOQVNbpO0WVHIivig5
L39WqS9u0hnA+O7MCA/KlrAR4bXaeVVhwfUPYBKIpaaTWFQR5cTR1UFZJL/OF9vA
fpOwznoD66DDCnQVpbCjtDYWX+x6imxn8HCYxhMol6ZnTbSsFW6VZjFMjQIDAQAB
AoGAVOj2Yvuigi6wJD99AO2fgF64sYCm/BKkX3dFEw0vxTPIh58kiRP554Xt5ges
7ZCqL9QpqrChUikO4kJ+nB8Uq2AvaZHbpCEUmbip06IlgdA440o0r0CPo1mgNxGu
lhiWRN43Lruzfh9qKPhleg2dvyFGQxy5Gk6KW/t8IS4x4r0CQQD/dceBA+Ndj3Xp
ubHfxqNz4GTOxndc/AXAowPGpge2zpgIc7f50t8OHhG6XhsfJ0wyQEEvodDhZPYX
kKBnXNHzAkEAyCA76vAwuxqAd3MObhiebniAU3SnPf2u4fdL1EOm92dyFs1JxyyL
gu/DsjPjx6tRtn4YAalxCzmAMXFSb1qHfwJBAM3qx3z0gGKbUEWtPHcP7BNsrnWK
vw6By7VC8bk/ffpaP2yYspS66Le9fzbFwoDzMVVUO/dELVZyBnhqSRHoXQcCQQCe
A2WL8S5o7Vn19rC0GVgu3ZJlUrwiZEVLQdlrticFPXaFrn3Md82ICww3jmURaKHS
N+l4lnMda79eSp3OMmq9AkA0p79BvYsLshUJJnvbk76pCjR28PK4dV1gSDUEqQMB
qy45ptdwJLqLJCeNoR0JUcDNIRhOCuOPND7pcMtX6hI/
-----END RSA PRIVATE KEY-----
serviceProviderKeyPassword: password
serviceProviderCertificate: |
-----BEGIN CERTIFICATE-----
MIIDSTCCArKgAwIBAgIBADANBgkqhkiG9w0BAQQFADB8MQswCQYDVQQGEwJhdzEO
MAwGA1UECBMFYXJ1YmExDjAMBgNVBAoTBWFydWJhMQ4wDAYDVQQHEwVhcnViYTEO
MAwGA1UECxMFYXJ1YmExDjAMBgNVBAMTBWFydWJhMR0wGwYJKoZIhvcNAQkBFg5h
cnViYUBhcnViYS5hcjAeFw0xNTExMjAyMjI2MjdaFw0xNjExMTkyMjI2MjdaMHwx
CzAJBgNVBAYTAmF3MQ4wDAYDVQQIEwVhcnViYTEOMAwGA1UEChMFYXJ1YmExDjAM
BgNVBAcTBWFydWJhMQ4wDAYDVQQLEwVhcnViYTEOMAwGA1UEAxMFYXJ1YmExHTAb
BgkqhkiG9w0BCQEWDmFydWJhQGFydWJhLmFyMIGfMA0GCSqGSIb3DQEBAQUAA4GN
ADCBiQKBgQDHtC5gUXxBKpEqZTLkNvFwNGnNIkggNOwOQVNbpO0WVHIivig5L39W
qS9u0hnA+O7MCA/KlrAR4bXaeVVhwfUPYBKIpaaTWFQR5cTR1UFZJL/OF9vAfpOw
znoD66DDCnQVpbCjtDYWX+x6imxn8HCYxhMol6ZnTbSsFW6VZjFMjQIDAQABo4Ha
MIHXMB0GA1UdDgQWBBTx0lDzjH/iOBnOSQaSEWQLx1syGDCBpwYDVR0jBIGfMIGc
gBTx0lDzjH/iOBnOSQaSEWQLx1syGKGBgKR+MHwxCzAJBgNVBAYTAmF3MQ4wDAYD
VQQIEwVhcnViYTEOMAwGA1UEChMFYXJ1YmExDjAMBgNVBAcTBWFydWJhMQ4wDAYD
VQQLEwVhcnViYTEOMAwGA1UEAxMFYXJ1YmExHTAbBgkqhkiG9w0BCQEWDmFydWJh
QGFydWJhLmFyggEAMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEEBQADgYEAYvBJ
0HOZbbHClXmGUjGs+GS+xC1FO/am2suCSYqNB9dyMXfOWiJ1+TLJk+o/YZt8vuxC
KdcZYgl4l/L6PxJ982SRhc83ZW2dkAZI4M0/Ud3oePe84k8jm3A7EvH5wi5hvCkK
RpuRBwn3Ei+jCRouxTbzKPsuCVB+1sNyxMTXzf0=
-----END CERTIFICATE-----
#! The secret that an external login server will use to authenticate to the uaa using the id `login`
LOGIN_SECRET: loginsecret

jwt:
token:
signing-key: tokenKey

database:
maxactive: 100
maxidle: 10
minidle: 0
removeabandoned: false
logabandoned: true
abandonedtimeout: 300
username: #@ data.values.database.username
password: #@ data.values.database.password
#@ end
5 changes: 5 additions & 0 deletions k8s/templates/values/values.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#@data/values
---
database:
username: uaa
password: password
50 changes: 50 additions & 0 deletions k8s/test/config_map_matcher_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package k8s_test

import (
"fmt"
"github.com/onsi/gomega/format"
"github.com/onsi/gomega/types"
v1 "k8s.io/api/core/v1"
)

type DataMatcherConfig func(*UaaYmlMatcher)

type ConfigMapMatcher struct {
dataMatcher *UaaYmlMatcher

executed types.GomegaMatcher
}


func RepresentingConfigMap() *ConfigMapMatcher {
return &ConfigMapMatcher{NewUaaYmlMatcher(), nil}
}

func (matcher *ConfigMapMatcher) WithDataMatching(config DataMatcherConfig) *ConfigMapMatcher {
config(matcher.dataMatcher)

return matcher
}

func (matcher *ConfigMapMatcher) Match(actual interface{}) (success bool, err error) {
configMap, ok := actual.(*v1.ConfigMap)
if !ok {
return false, fmt.Errorf("Expected a ConfigMap. Got\n%s", format.Object(actual, 1))
}

matcher.executed = matcher.dataMatcher
pass, err := matcher.dataMatcher.Match(configMap.Data)
if !pass || err != nil {
return pass, err
}

return true, nil
}

func (matcher *ConfigMapMatcher) FailureMessage(actual interface{}) (message string) {
return matcher.executed.FailureMessage(actual)
}

func (matcher *ConfigMapMatcher) NegatedFailureMessage(actual interface{}) (message string) {
return matcher.executed.NegatedFailureMessage(actual)
}
63 changes: 63 additions & 0 deletions k8s/test/config_map_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package k8s_test

import (
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
. "github.com/onsi/gomega/gstruct"

"path/filepath"
)

var _ = Describe("Uaa ConfigMap", func() {
var configPath, uaaLibPath, valuesPath string
var database Database

BeforeEach(func() {
configPath = pathToTemplate("config.yml")
uaaLibPath = pathToTemplate("uaa.lib.yml")
valuesPath = pathToTemplate(filepath.Join("values", "values.yml"))
database = Database{Username: "uaa", Password: "password"}
})

It("Renders a config map with default values", func() {
ctx := NewRenderingContext(configPath, uaaLibPath, valuesPath)

Expect(ctx).To(
ProduceYAML(
RepresentingConfigMap().WithDataMatching(func(uaaYml *UaaYmlMatcher) {
uaaYml.WithFields(Fields{
"LoginSecret": Equal("loginsecret"),
"Issuer": Equal(Issuer{Uri: "http://localhost:8080/uaa"}),
"Database": MatchFields(IgnoreExtras, Fields{
"Username": Equal(database.Username),
"Password": Equal(database.Password),
}),
})
}),
))
})

It("Can renders a config map with overriden values", func() {
database.Username = "database-username"
database.Password = "database-password"

ctx := NewRenderingContext(configPath, uaaLibPath, valuesPath).WithData(map[string]string{
"database.username": database.Username,
"database.password": database.Password,
})

Expect(ctx).To(
ProduceYAML(
RepresentingConfigMap().WithDataMatching(func(uaaYml *UaaYmlMatcher) {
uaaYml.WithFields(Fields{
"LoginSecret": Equal("loginsecret"),
"Issuer": Equal(Issuer{Uri: "http://localhost:8080/uaa"}),
"Database": MatchFields(IgnoreExtras, Fields{
"Username": Equal(database.Username),
"Password": Equal(database.Password),
}),
})
}),
))
})
})
2 changes: 1 addition & 1 deletion k8s/test/deployment_matcher_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ func (matcher *DeploymentMatcher) Match(actual interface{}) (bool, error) {
return false, fmt.Errorf("Expected a deployment. Got\n%s", format.Object(actual, 1))
}

matcher.executed = matcher.pod
matcher.executed = matcher.pod // so we can have good pod-specific failure messages
if pass, err := matcher.pod.Match(deployment.Spec.Template); !pass || err != nil {
return pass, err
}
Expand Down
2 changes: 1 addition & 1 deletion k8s/test/k8s_suite_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ var templateBasePath string
func init() {
_, filename, _, ok := runtime.Caller(0)
if !ok {
panic("Could not initialize k8s_test package: can't find location of this file")
panic("Could not initiaize k8s_test package: can't find location of this file")
}

relative := filepath.Join(filepath.Dir(filename), "..", "templates")
Expand Down
4 changes: 2 additions & 2 deletions k8s/test/produce_yaml_matcher_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ func (matcher *ProduceYAMLMatcher) Match(actual interface{}) (bool, error) {

func (matcher *ProduceYAMLMatcher) FailureMessage(actual interface{}) string {
msg := fmt.Sprintf(
"There is a problem with this YAML:\n\n%s\n\n%s",
"FailureMessage: There is a problem with this YAML:\n\n%s\n\n%s",
matcher.rendered,
matcher.matcher.FailureMessage(actual),
)
Expand All @@ -65,7 +65,7 @@ func (matcher *ProduceYAMLMatcher) FailureMessage(actual interface{}) string {

func (matcher *ProduceYAMLMatcher) NegatedFailureMessage(actual interface{}) string {
msg := fmt.Sprintf(
"There is a problem with this YAML:\n\n%s\n\n%s",
"NegatedFailureMessage: There is a problem with this YAML:\n\n%s\n\n%s",
matcher.rendered,
matcher.matcher.NegatedFailureMessage(actual),
)
Expand Down
45 changes: 45 additions & 0 deletions k8s/test/uaa_config_structs_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package k8s_test

type UaaConfig struct {
Issuer Issuer `yaml:"issuer"`
Encryption Encryption `yaml:"encryption"`
Login Login `yaml:"login"`
LoginSecret string `yaml:"LOGIN_SECRET"`
Jwt Jwt `yaml:"jwt"`
Database Database `yaml:"database"`
}

type Issuer struct {
Uri string `yaml:"uri"`
}

type Encryption struct {
ActiveKeyLabel string `yaml:"active_key_label"`
EncryptionKeys []struct {
Label string `yaml:"label"`
Passphrase string `yaml:"passphrase"`
} `yaml:"encryption_keys"`
}

type Jwt struct {
Token struct {
SigningKey string `yaml:"signing-key"`
} `yaml:"token"`
}

type Login struct {
ServiceProviderKey string `yaml:"serviceProviderKey"`
ServiceProviderKeyPassword string `yaml:"serviceProviderKeyPassword"`
ServiceProviderCertificate string `yaml:"serviceProviderKeyCertificate"`
}

type Database struct {
MaxActive int `yaml:"maxactive"`
MaxIdle int `yaml:"maxidle"`
MinIdle int `yaml:"minidle"`
RemoveAbandoned bool `yaml:"removeabandoned"`
LogAbandoned bool `yaml:"logabandoned"`
AbandonedTimeout int `yaml:"abandonedtimeout"`
Username string `yaml:"username"`
Password string `yaml:"password"`
}
53 changes: 53 additions & 0 deletions k8s/test/uaa_yml_matcher_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package k8s_test

import (
"github.com/onsi/gomega/gstruct"
"github.com/onsi/gomega/types"

"gopkg.in/yaml.v2"
)

const UaaYmlConfigKey = "uaa.yml"

type UaaYmlMatcher struct {
fields map[string]types.GomegaMatcher
configFields gstruct.Fields
executed types.GomegaMatcher
}

func NewUaaYmlMatcher() *UaaYmlMatcher {
return &UaaYmlMatcher{
fields: map[string]types.GomegaMatcher{},
configFields: gstruct.Fields{},
executed: nil,
}
}

func (matcher *UaaYmlMatcher) WithFields(fields gstruct.Fields) *UaaYmlMatcher {
matcher.configFields = fields
return matcher
}

func (matcher *UaaYmlMatcher) Match(actual interface{}) (success bool, err error) {
configMapData, ok := actual.(map[string]string)
if !ok {
panic("expected a map[string]string")
}

uaaYml := UaaConfig{}
err = yaml.Unmarshal([]byte(configMapData[UaaYmlConfigKey]), &uaaYml)
if err != nil {
panic("Failed to unmarshal")
}

matcher.executed = gstruct.MatchFields(gstruct.IgnoreExtras, matcher.configFields)
return matcher.executed.Match(uaaYml)
}

func (matcher *UaaYmlMatcher) FailureMessage(actual interface{}) (message string) {
return matcher.executed.FailureMessage(actual)
}

func (matcher *UaaYmlMatcher) NegatedFailureMessage(actual interface{}) (message string) {
return matcher.executed.NegatedFailureMessage(actual)
}

0 comments on commit 5391b93

Please sign in to comment.