-
Notifications
You must be signed in to change notification settings - Fork 3.4k
Envoy TLS support with header imposition #9486
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
Conversation
pkg/envoy/server.go
Outdated
} | ||
} | ||
|
||
func GetEnvoyHTTPRules(certManager policy.CertificateManager, l7Rules *api.L7Rules) *cilium.PortNetworkPolicyRule_HttpRules { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
exported function GetEnvoyHTTPRules should have comment or be unexported
egressTLSClusterName = "egress-cluster-tls" | ||
ingressClusterName = "ingress-cluster" | ||
ingressTLSClusterName = "ingress-cluster-tls" | ||
EnvoyTimeout = 300 * time.Second // must be smaller than endpoint.EndpointGenerationTimeout |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
exported const EnvoyTimeout should have comment (or a comment on this block) or be unexported
pkg/policy/repository.go
Outdated
return p.getEnvoyHTTPRules(p.certManager, l7Rules) | ||
} | ||
|
||
func (p *Repository) SetEnvoyRulesFunc(f func(CertificateManager, *api.L7Rules) *cilium.PortNetworkPolicyRule_HttpRules) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
exported method Repository.SetEnvoyRulesFunc should have comment or be unexported
pkg/policy/repository.go
Outdated
return p.certManager.GetTLSContext(context.TODO(), tls) | ||
} | ||
|
||
func (p *Repository) GetEnvoyHTTPRules(l7Rules *api.L7Rules) *cilium.PortNetworkPolicyRule_HttpRules { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
exported method Repository.GetEnvoyHTTPRules should have comment or be unexported
pkg/policy/repository.go
Outdated
} | ||
|
||
// GetSelectorCache() returns the selector cache used by the Repository | ||
func (p *Repository) GetSelectorCache() *SelectorCache { | ||
return p.selectorCache | ||
} | ||
|
||
// GetSelectorCache() returns the selector cache used by the Repository |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
comment on exported method Repository.GetTLSContext should be of the form "GetTLSContext ..."
|
||
// PolicyContext is an interface policy resolution functions use to access the Repository. | ||
// This way testing code can run without mocking a full Repository. | ||
type PolicyContext interface { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
type name will be used as policy.PolicyContext by other packages, and that stutters; consider calling this Context
) | ||
|
||
type CertificateManager interface { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
exported type CertificateManager should have comment or be unexported
return json.Marshal(&redacted) | ||
} | ||
|
||
type PerEpData struct { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
exported type PerEpData should have comment or be unexported
// MarshalJSON marsahls a redacted version of the TLSContext. We want | ||
// to see which fields are present, but not reveal their values in any | ||
// logs, etc. | ||
func (t *TLSContext) MarshalJSON() ([]byte, error) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
receiver name t should be consistent with previous receiver name a for TLSContext
|
||
"github.com/sirupsen/logrus" | ||
) | ||
|
||
// TLS context holds the secret values resolved from an 'api.TLSContext' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
comment on exported type TLSContext should be of the form "TLSContext ..." (with optional leading article)
test-me-please |
4c6a6c7
to
760dbd3
Compare
|
||
headerMatches := make([]*cilium.HeaderMatch, 0, len(h.HeaderMatches)) | ||
for _, hdr := range h.HeaderMatches { | ||
var mismatch_action cilium.HeaderMatch_MismatchAction |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
don't use underscores in Go names; var mismatch_action should be mismatchAction
|
||
headerMatches := make([]*cilium.HeaderMatch, 0, len(h.HeaderMatches)) | ||
for _, hdr := range h.HeaderMatches { | ||
var mismatch_action cilium.HeaderMatch_MismatchAction |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
don't use underscores in Go names; var mismatch_action should be mismatchAction
|
||
headerMatches := make([]*cilium.HeaderMatch, 0, len(h.HeaderMatches)) | ||
for _, hdr := range h.HeaderMatches { | ||
var mismatch_action cilium.HeaderMatch_MismatchAction |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
don't use underscores in Go names; var mismatch_action should be mismatchAction
type MismatchAction string | ||
|
||
const ( | ||
MismatchActionLog MismatchAction = "LOG" // Keep checking other matches |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
exported const MismatchActionLog should have comment (or a comment on this block) or be unexported
type MismatchAction string | ||
|
||
const ( | ||
MismatchActionLog MismatchAction = "LOG" // Keep checking other matches |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
exported const MismatchActionLog should have comment (or a comment on this block) or be unexported
6f01efc
to
85a6486
Compare
test-me-please |
85a6486
to
0f2ed90
Compare
test-me-please |
0f2ed90
to
38f22bd
Compare
test-me-please |
test-me-please |
pkg/policy/api/l4.go
Outdated
} | ||
|
||
// Equal returns true if 'a' and 'b' have the same contents. | ||
func (a *TLSContext) Equal(b *TLSContext) bool { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To avoid copying the structures as would happen if they would be passed by value instead of by reference. I see that passing by value would prevent (accidental) mutations which would be nice.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Upon examining the call sites I recalled that the entities being compared are already pointers, so it is best to keep this Equal()
function to avoid code repetition and keep the call sites more readable.
This option will set the root certificate used to search for TLS certificates defined in a CNP for L7 TLS policy enforcement. Signed-off-by: André Martins <andre@cilium.io>
Signed-off-by: André Martins <andre@cilium.io>
Add API definitions for k8s secrets and plumb them into Envoy policy updates. Add certificate manager to find certificates either locally or in k8s Map keys "tls.key" and "tls.crt" are used for the private key and the certificate, respectively, when creating a TLS secret like so: $ kubectl create secret tls test-tls --key="file1" --cert="file2" Support explicit overrides for the default item names. If given, these must be found. Signed-off-by: Jarno Rajahalme <jarno@covalent.io> Signed-off-by: André Martins <andre@cilium.io>
Add PolicyContext, a collection of references to resources needed during policy computation. Initially this holds just a SelectorCache, but later commits will add more items without then needing to update and bloat all the function prototypes. Signed-off-by: Jarno Rajahalme <jarno@covalent.io>
Resolve TLS contexts earlier in the process. Get the default namespace from the security identity rather than the rule. This allows for a default namespace to be well defined even if none of the rules have a namespace label. Signed-off-by: Jarno Rajahalme <jarno@covalent.io>
Supporting secrets is easier if we translate HTTP policies while in the policy computation context. Translating HTTP policies erlier also reduces unnecessary work of re-translating them when policy remains but IDs change. Signed-off-by: Jarno Rajahalme <jarno@covalent.io>
Allow replacing logging, deleting, adding, and replacing mismatching headers. Now that we can have rules with side-effect, we must track if HTTP rules can be short circuited. If no rules have side-effects, then the policy evaluationn can be stopped as soon as a decision to pass traffic has been found. If rules include side-effects, we must evaluate all applicable rules. Signed-off-by: Jarno Rajahalme <jarno@covalent.io>
a158c2d
to
b65236a
Compare
} | ||
} | ||
|
||
func GetEnvoyHTTPRules(certManager policy.CertificateManager, l7Rules *api.L7Rules, ns string) (*cilium.HttpNetworkPolicyRules, bool) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
exported function GetEnvoyHTTPRules should have comment or be unexported
} | ||
} | ||
|
||
func GetEnvoyHTTPRules(certManager policy.CertificateManager, l7Rules *api.L7Rules, ns string) (*cilium.HttpNetworkPolicyRules, bool) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
exported function GetEnvoyHTTPRules should have comment or be unexported
test-me-please |
@jrajahalme it's a real CI failure:
|
Signed-off-by: Jarno Rajahalme <jarno@covalent.io>
Add simple TLS test to access an external resource via the proxy. Signed-off-by: Jarno Rajahalme <jarno@covalent.io>
b65236a
to
db040ef
Compare
test-me-please |
CI errors seem unrelated, external connectivity issues (1.1.1.1), etc. Trying again. |
test-me-please |
1 similar comment
test-me-please |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM!
I have a bunch of super trivial feedback below that could be addressed in a follow-up PR, the only one that would be meaningful for the next RC would be if we wish to change the CLI arg name.
err = fmt.Errorf("certificates not found locally in %s nor in k8s secret %s/%s ", m.rootPath, ns, name) | ||
return "", "", "", err | ||
} | ||
err = fmt.Errorf("certificates not found in k8s secret %s/%s", ns, name) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there any meaningful distinction between the error on line 162 and the error here, or could we unconditionally use the error on line 162 to replace lines 161-165?
It seems to me like if either local or k8s-based certificate detection was successful (and TLS is configured in the specified policy) then this function would have already returned by this point. It's the fact that neither provided certificates that leads us to this error condition.
Also the path should probably be certPath
rather than m.rootPath
, as that's the full path that was searched for the local certs.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Cleaned up in the follow-up PR #9807
@@ -89,6 +89,10 @@ const ( | |||
// BPFRoot is the Path to BPF filesystem | |||
BPFRoot = "bpf-root" | |||
|
|||
// CertsDirectory is the root directory used to find out certificates used | |||
// in L7 HTTPs policy enforcement. | |||
CertsDirectory = "certificates-directory" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: Should this CLI arg be more specific, like policy-certificates-dir
, to ensure there's no mixups with the kvstore certs?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe, will need to discuss this more. We could also generalizer this to all "secrets", not just certificates. In that case a name like "local-secrets-dir" would be a better match?
type PolicyContext interface { | ||
GetSelectorCache() *SelectorCache | ||
GetTLSContext(tls *api.TLSContext) (ca, public, private string, err error) | ||
GetEnvoyHTTPRules(l7Rules *api.L7Rules) (*cilium.HttpNetworkPolicyRules, bool) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: I think it'd be useful to document particularly the canShortcut
bool here in context of what users or implementations of this interface can and should do. The whole interface could do with a bit of documentation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added documentation to all functions in this interface.
} | ||
|
||
pnp.Rules = append(pnp.Rules, rule) | ||
} | ||
} | ||
|
||
// Short-circuit rules if a rule allows all and all other rules can be short-circuited | ||
if allowAll && canShortCircuit { | ||
log.Info("Short circuiting HTTP rules due to rule allowing all and no other rules needing attention") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks like a debug-level log, I don't think it's meaningful to most users and it's prone to repeating itself in the logs when a policy is evaluated.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right, changed to Debug
Properties: Secret, | ||
}, | ||
"value": { | ||
Description: "Value containst the header value that must be present in the request. If both Secret " + |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Description: "Value containst the header value that must be present in the request. If both Secret " + | |
Description: "Value contains the header value that must be present in the request. If both Secret " + |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed.
h.Value != o.Value || | ||
h.Secret != nil && o.Secret == nil || | ||
h.Secret == nil && o.Secret != nil || | ||
h.Secret != nil && o.Secret != nil && *h.Secret != *o.Secret { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can this use !h.Secret.Equal(o.Secret)
? (Ignore if this is autogenerated..)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Secret.Equal()
did not exist, but I factored it out of this for clarity.
// TerminatingTLS is the TLS context for the connection terminated by | ||
// the L7 proxy. For egress policy this specifies the server-side TLS | ||
// parameters to be applied on the connections originated from the local | ||
// POD and terminated by the L7 proxy. For ingress policy this specifies |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: This API wording usually uses the Cilium endpoint
terminology rather than POD
. (Same below)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changed, thanks!
@jrajahalme merged 🎉 At this point it's probably more useful to merge this and get rc2 out and allow people to try it out and test it. It will be easier to iterate on in the master tree. Please do follow up on the remaining feedback items above in a follow up PR. |
@joestringer Addressed your comments in #9807 |
Add API support for TLS proxying for HTTP, with support for header modifications and (k8s) secrets.
This change is