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

Adding (m)TLS Support #615

Merged
merged 24 commits into from
Nov 15, 2022
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 10 additions & 11 deletions config/backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,21 +12,20 @@ var (
_ BackendReference = &Backend{}
_ Body = &Backend{}
_ Inline = &Backend{}

BackendInlineSchema = Backend{}.Schema(true)
)

// Backend represents the <Backend> object.
type Backend struct {
DisableCertValidation bool `hcl:"disable_certificate_validation,optional" docs:"Disables the peer certificate validation. Must not be used in backend refinement."`
DisableConnectionReuse bool `hcl:"disable_connection_reuse,optional" docs:"Disables reusage of connections to the origin. Must not be used in backend refinement."`
Health *Health `hcl:"beta_health,block"`
HTTP2 bool `hcl:"http2,optional" docs:"Enables the HTTP2 support. Must not be used in backend refinement."`
MaxConnections int `hcl:"max_connections,optional" docs:"The maximum number of concurrent connections in any state (_active_ or _idle_) to the origin. Must not be used in backend refinement." default:"0"`
Name string `hcl:"name,label,optional"`
OpenAPI *OpenAPI `hcl:"openapi,block"`
RateLimits RateLimits `hcl:"beta_rate_limit,block"`
Remain hcl.Body `hcl:",remain"`
DisableCertValidation bool `hcl:"disable_certificate_validation,optional" docs:"Disables the peer certificate validation. Must not be used in backend refinement."`
DisableConnectionReuse bool `hcl:"disable_connection_reuse,optional" docs:"Disables reusage of connections to the origin. Must not be used in backend refinement."`
Health *Health `hcl:"beta_health,block"`
HTTP2 bool `hcl:"http2,optional" docs:"Enables the HTTP2 support. Must not be used in backend refinement."`
MaxConnections int `hcl:"max_connections,optional" docs:"The maximum number of concurrent connections in any state (_active_ or _idle_) to the origin. Must not be used in backend refinement." default:"0"`
Name string `hcl:"name,label,optional"`
OpenAPI *OpenAPI `hcl:"openapi,block"`
RateLimits RateLimits `hcl:"beta_rate_limit,block"`
Remain hcl.Body `hcl:",remain"`
TLS *BackendTLS `hcl:"tls,block"`
}

// Reference implements the <BackendReference> interface.
Expand Down
9 changes: 9 additions & 0 deletions config/body/body.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,15 @@ func BlocksOfType(body *hclsyntax.Body, blockType string) []*hclsyntax.Block {
return blocks
}

func AttributeByName(body *hclsyntax.Body, needle string) *hclsyntax.Attribute {
for _, attr := range body.Attributes {
if attr.Name == needle {
return attr
}
}
return nil
}

func RenameAttribute(body *hclsyntax.Body, old, new string) {
if attr, ok := body.Attributes[old]; ok {
attr.Name = new
Expand Down
17 changes: 17 additions & 0 deletions config/certificate.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package config

type ClientCertificate struct {
Name string `hcl:",label,optional"`
CA string `hcl:"ca_certificate,optional"`
CAFile string `hcl:"ca_certificate_file,optional"`
Leaf string `hcl:"leaf_certificate,optional"`
LeafFile string `hcl:"leaf_certificate_file,optional"`
}

type ServerCertificate struct {
Name string `hcl:",label,optional"`
PublicKey string `hcl:"public_key,optional"`
PublicKeyFile string `hcl:"public_key_file,optional"`
PrivateKey string `hcl:"private_key,optional"`
PrivateKeyFile string `hcl:"private_key_file,optional"`
}
1 change: 1 addition & 0 deletions config/configload/load.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ const (
server = "server"
settings = "settings"
spa = "spa"
tls = "tls"
tokenRequest = "beta_token_request"
// defaultNameLabel maps the hcl label attr 'name'.
defaultNameLabel = "default"
Expand Down
28 changes: 26 additions & 2 deletions config/configload/validate.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"github.com/hashicorp/hcl/v2/hclsyntax"
"github.com/zclconf/go-cty/cty"

bodySyntax "github.com/avenga/couper/config/body"
"github.com/avenga/couper/eval"
"github.com/avenga/couper/utils"
)
Expand Down Expand Up @@ -64,6 +65,11 @@ func validateBody(body *hclsyntax.Body, afterMerge bool) error {
}
uniqueBackends[label] = struct{}{}
}

if err := validateBackendTLS(innerBlock); err != nil {
return err
}

case "basic_auth", "beta_oauth2", "oidc", "saml":
err := checkAC(uniqueACs, label, labelRange, afterMerge)
if err != nil {
Expand Down Expand Up @@ -110,8 +116,8 @@ func validateBody(body *hclsyntax.Body, afterMerge bool) error {
return err
}
} else if innerBlock.Type == api {
apiBasePath, err := getBasePath(innerBlock, afterMerge)
if err != nil {
var apiBasePath string
if apiBasePath, err = getBasePath(innerBlock, afterMerge); err != nil {
return err
}

Expand Down Expand Up @@ -306,3 +312,21 @@ func validMethods(methods []string, attr *hclsyntax.Attribute) error {

return nil
}

// validateBackendTLS determines irrational backend certificate configuration.
func validateBackendTLS(block *hclsyntax.Block) error {
validateCertAttr := bodySyntax.AttributeByName(block.Body, "disable_certificate_validation")
malud marked this conversation as resolved.
Show resolved Hide resolved
if tlsBlocks := bodySyntax.BlocksOfType(block.Body, "tls"); validateCertAttr != nil && len(tlsBlocks) > 0 {
var attrName string
if caCert := bodySyntax.AttributeByName(tlsBlocks[0].Body, "server_ca_certificate"); caCert != nil {
attrName = caCert.Name
} else if caCertFile := bodySyntax.AttributeByName(tlsBlocks[0].Body, "server_ca_certificate_file"); caCertFile != nil {
attrName = caCertFile.Name
}
if attrName != "" {
r := tlsBlocks[0].Range()
return newDiagErr(&r, fmt.Sprintf("configured 'disable_certificate_validation' along with '%s' attribute", attrName))
}
}
return nil
}
37 changes: 37 additions & 0 deletions config/configload/validate_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,43 @@ func Test_validateBody(t *testing.T) {
}`,
"couper.hcl:5,15-20: backend labels must be unique; ",
},
{
"backend disable cert validation with tls block and server_ca_certificate",
`server {}
definitions {
backend "foo" {
disable_certificate_validation = false # value does not matter
tls {
server_ca_certificate = "asdf"
}
}
}`,
"couper.hcl:5,6-7,7: configured 'disable_certificate_validation' along with 'server_ca_certificate' attribute; ",
},
{
"backend disable cert validation with tls block and server_ca_certificate_file",
`server {}
definitions {
backend "foo" {
disable_certificate_validation = true # value does not matter
tls {
server_ca_certificate_file = "asdf.crt"
}
}
}`,
"couper.hcl:5,6-7,7: configured 'disable_certificate_validation' along with 'server_ca_certificate_file' attribute; ",
},
{
"backend disable cert validation with tls block and w/o server_ca_certificate*",
`server {}
definitions {
backend "foo" {
disable_certificate_validation = true # value does not matter
tls {}
}
}`,
"",
},
{
"duplicate proxy labels",
`server {}
Expand Down
1 change: 1 addition & 0 deletions config/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ type Server struct {
Name string `hcl:"name,label,optional"`
Remain hcl.Body `hcl:",remain"`
SPAs SPAs `hcl:"spa,block"`
TLS *ServerTLS `hcl:"tls,block"`
}

// Servers represents a list of <Server> objects.
Expand Down
15 changes: 15 additions & 0 deletions config/tls.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package config

type ServerTLS struct {
Ocsp bool `hcl:"ocsp,optional"`
OcspTTL string `hcl:"ocsp_ttl,optional" type:"duration" default:"12h"`
malud marked this conversation as resolved.
Show resolved Hide resolved
ClientCertificate []*ClientCertificate `hcl:"client_certificate,block"`
ServerCertificates []*ServerCertificate `hcl:"server_certificate,block"`
}

type BackendTLS struct {
ServerCertificate string `hcl:"server_ca_certificate,optional"`
ServerCertificateFile string `hcl:"server_ca_certificate_file,optional"`
ClientCertificate string `hcl:"client_certificate,optional"`
ClientCertificateFile string `hcl:"client_certificate_file,optional"`
}
File renamed without changes.
File renamed without changes.