-
Notifications
You must be signed in to change notification settings - Fork 111
Added property to accept certificates for tls termination at tcp router #502
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -8,6 +8,7 @@ import ( | |
"errors" | ||
"fmt" | ||
"os" | ||
"path/filepath" | ||
"strings" | ||
"time" | ||
|
||
|
@@ -38,15 +39,27 @@ type BackendTLSConfig struct { | |
CACertificatePath string `yaml:"ca_cert_path"` | ||
ClientCertAndKeyPath string `yaml:"client_cert_and_key_path"` | ||
} | ||
type FrontendTLSConfig struct { | ||
Enabled bool `yaml:"enabled"` | ||
CertPath string `yaml:"cert_path"` | ||
} | ||
|
||
type FrontendTLSJob struct { | ||
Name string `yaml:"name"` | ||
CertChain string `yaml:"cert_chain"` | ||
PrivateKey string `yaml:"private_key"` | ||
} | ||
|
||
type Config struct { | ||
OAuth OAuthConfig `yaml:"oauth"` | ||
RoutingAPI RoutingAPIConfig `yaml:"routing_api"` | ||
HaProxyPidFile string `yaml:"haproxy_pid_file"` | ||
IsolationSegments []string `yaml:"isolation_segments"` | ||
ReservedSystemComponentPorts []uint16 `yaml:"reserved_system_component_ports"` | ||
DrainWaitDuration time.Duration `yaml:"drain_wait"` | ||
BackendTLS BackendTLSConfig `yaml:"backend_tls"` | ||
OAuth OAuthConfig `yaml:"oauth"` | ||
RoutingAPI RoutingAPIConfig `yaml:"routing_api"` | ||
HaProxyPidFile string `yaml:"haproxy_pid_file"` | ||
IsolationSegments []string `yaml:"isolation_segments"` | ||
ReservedSystemComponentPorts []uint16 `yaml:"reserved_system_component_ports"` | ||
DrainWaitDuration time.Duration `yaml:"drain_wait"` | ||
BackendTLS BackendTLSConfig `yaml:"backend_tls"` | ||
FrontendTLS []FrontendTLSConfig `yaml:"frontend_tls_pem"` | ||
FrontendTLSJob []FrontendTLSJob `yaml:"frontend_tls"` | ||
} | ||
|
||
const DrainWaitDefault = 20 * time.Second | ||
|
@@ -60,6 +73,13 @@ func New(path string) (*Config, error) { | |
return c, nil | ||
} | ||
|
||
func (c *Config) FrontendTLSJobBasePath() string { | ||
if bp := os.Getenv("FRONTEND_TLS_BASE_PATH"); bp != "" { | ||
return bp | ||
} | ||
return "/var/vcap/jobs/tcp_router/config/keys/tcp-router/frontend" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. do we have to worry about proper permissions? Copying the sibling's (
|
||
} | ||
|
||
func (c *Config) initConfigFromFile(path string) error { | ||
var e error | ||
|
||
|
@@ -81,6 +101,53 @@ func (c *Config) initConfigFromFile(path string) error { | |
c.DrainWaitDuration = DrainWaitDefault | ||
} | ||
|
||
if len(c.FrontendTLSJob) > 0 { | ||
var outputs []FrontendTLSConfig | ||
basePath := c.FrontendTLSJobBasePath() | ||
for i, cert := range c.FrontendTLSJob { | ||
|
||
name := strings.TrimSpace(cert.Name) | ||
certChain := strings.TrimSpace(cert.CertChain) | ||
privateKey := strings.TrimSpace(cert.PrivateKey) | ||
|
||
if name == "" || certChain == "" || privateKey == "" { | ||
return fmt.Errorf("frontend_tls[%d] must include name, cert_chain, and private_key", i) | ||
} | ||
|
||
block, _ := pem.Decode([]byte(certChain)) | ||
if block == nil { | ||
return errors.New("failed to parse PEM block") | ||
} | ||
cert, err := x509.ParseCertificate(block.Bytes) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
hasSAN := certHasSAN(cert) | ||
if !hasSAN { | ||
return fmt.Errorf("frontend_tls[%d].cert_chain must include a subjectAltName extension", i) | ||
} | ||
|
||
dirPath := filepath.Join(basePath, name) | ||
os.MkdirAll(dirPath, 0755) | ||
|
||
certFilePath := filepath.Join(dirPath, fmt.Sprintf("%s.pem", name)) | ||
keyFilePath := filepath.Join(dirPath, fmt.Sprintf("%s.pem.key", name)) | ||
|
||
os.WriteFile(certFilePath, []byte(certChain), 0644) | ||
|
||
os.WriteFile(keyFilePath, []byte(privateKey), 0600) | ||
|
||
outputs = append(outputs, FrontendTLSConfig{ | ||
Enabled: true, | ||
CertPath: certFilePath, | ||
}) | ||
} | ||
|
||
c.FrontendTLS = outputs | ||
|
||
} | ||
|
||
if c.BackendTLS.Enabled { | ||
AshishNaware marked this conversation as resolved.
Show resolved
Hide resolved
|
||
if c.BackendTLS.CACertificatePath != "" { | ||
pemData, err := os.ReadFile(c.BackendTLS.CACertificatePath) | ||
|
@@ -156,3 +223,17 @@ func (c *Config) initConfigFromFile(path string) error { | |
|
||
return nil | ||
} | ||
|
||
func certHasSAN(cert *x509.Certificate) bool { | ||
hasSANExtension := false | ||
for _, ext := range cert.Extensions { | ||
if ext.Id.String() == "2.5.29.17" { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Some documentation here may help. Where did this id There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is the OID of the SAN field coming from the ASN1 spec. It will never change. https://oidref.com/2.5.29.17 I think that the check that computes There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I added this check to be consistent with the gorouter https://github.com/cloudfoundry/routing-release/blob/develop/jobs/gorouter/templates/gorouter.yml.erb#L445 |
||
hasSANExtension = true | ||
break | ||
} | ||
} | ||
|
||
hasDNSEntries := len(cert.DNSNames) > 0 | ||
|
||
return hasSANExtension || hasDNSEntries | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
oauth: | ||
token_endpoint: "uaa.service.cf.internal" | ||
client_name: "someclient" | ||
client_secret: "somesecret" | ||
port: 8443 | ||
skip_ssl_validation: true | ||
ca_certs: "some-ca-cert" | ||
|
||
routing_api: | ||
uri: http://routing-api.service.cf.internal | ||
port: 3000 | ||
auth_disabled: false | ||
client_cert_path: /a/client_cert | ||
client_private_key_path: /b/private_key | ||
ca_cert_path: /c/ca_cert | ||
|
||
haproxy_pid_file: /path/to/pid/file | ||
isolation_segments: ["foo-iso-seg"] | ||
reserved_system_component_ports: [8080, 8081] | ||
frontend_tls: | ||
- name: "prod" | ||
cert_chain: |- | ||
-----BEGIN CERTIFICATE----- | ||
MIIEITCCAgmgAwIBAgIRAMGCNmHhXZnK1fSdCinKK9owDQYJKoZIhvcNAQELBQAw | ||
EjEQMA4GA1UEAxMHdGVzdC1jYTAeFw0yMTEwMjExNjU2NTJaFw0yMzA0MjExNjI5 | ||
MDVaMBMxETAPBgNVBAMTCHRlc3QuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A | ||
MIIBCgKCAQEAwY9FO90qNGnztTlPSUODTLvdKex08dA+/hQ2URMBStqI5g6dJZP9 | ||
RcLVyRpp9719KKs2PL2ol/QEfUMXKSB1pld6kRGFEXbPkz8rxLhYt79UzjAC8lWj | ||
z/NbyIvNVzqgYlB7Tk+sgIBF3LSV3Zh4ZsrNoXMu/VDG+ODm/1dcLZJE3QXaMM6Z | ||
nbvdy/eUOhJ12BzgM+1PKjNi93azOB6uBiXZ1QgzWbmWJHnGmvX/HUdT8s4e1snt | ||
5mAsS7hmsrxpu2QD9b3gGUIgy6z6ZuFp1kq0S5HxoFDNjvi88p2E4Jk+unfFMaO9 | ||
4+OyOZWW5TqyyhTYCrhBEcZ4m5hm82v76wIDAQABo3EwbzAOBgNVHQ8BAf8EBAMC | ||
A7gwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMB0GA1UdDgQWBBRZ7D+U | ||
LkHi0vbszx8bMG2LZSqUejAfBgNVHSMEGDAWgBQSH/Cc1RDZyRh9u9sfHeS3eWYz | ||
TDANBgkqhkiG9w0BAQsFAAOCAgEA1YluE0iSE4HEc2N2fdYhmwF2LP3pjUfmzF/g | ||
NcxjhydQUoxyOxf6+1RsNe7taXQRLhmpN2JaiE8yCf+wDciIhRWnqyHgJEKoJgK6 | ||
4liu7JUpOFgAloe8koKhWxEerkU4VcPy8kN5gZ8I6b8Mso4hTq2O5NhntqKDFRS0 | ||
v0ZpMkz1PhWwI79No8WXU0tUwx5pT3mcwjCr57mnyYWmeHqAXgnUI4U0QnSyr3sa | ||
jmjpLk2TncpC3CSTr1AbOhm/yglsrbLllvufHUbYv5QNlzkOauvgCzvXQ4ScFttn | ||
epDzPE8PrsY8N/26BwOCc6ftQqabhpIKzT6w6DN5xYRZi5fyzRNho5+5RuBDRKmL | ||
AGfrpiixm4zzgUL7jVlOVlZXQ/vkQ+h4+aqS2ssRwPoqGxilFxfUMgO+hr3jZkxz | ||
o9Z7Yeljt7rzeYESEDtkwou+75LHzfKduVT8Kxwn8LwiB0trgbcx3qj2ab8fucM4 | ||
UUXAXr6ve5DcdkKevLoNypq2kCh7hySjrjDp/gnCMhuc0ch8oV2RV2ZlA+QOD+J4 | ||
VAgYLhy03ZZaUFvmGhCx+FEkkzq/d2GGWuNd1T2MMkTBplf+pK+3l+jHxYuSc8DR | ||
gPYhs8i50bWlTVu/yJgJGBzAmWcybfi7NmUkQyYHmpLP3GRbtdI+eESF9vAJpKSs | ||
ONppgXo= | ||
-----END CERTIFICATE----- | ||
private_key: "some key" |
Uh oh!
There was an error while loading. Please reload this page.