/
redirect_traffic.go
147 lines (122 loc) · 5.5 KB
/
redirect_traffic.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0
package webhook
import (
"encoding/json"
"fmt"
"strconv"
"github.com/hashicorp/consul/sdk/iptables"
corev1 "k8s.io/api/core/v1"
"github.com/hashicorp/consul-k8s/control-plane/connect-inject/common"
"github.com/hashicorp/consul-k8s/control-plane/connect-inject/constants"
)
// addRedirectTrafficConfigAnnotation creates an iptables.Config in JSON format based on proxy configuration.
// iptables.Config:
//
// ConsulDNSIP: an environment variable named RESOURCE_PREFIX_DNS_SERVICE_HOST where RESOURCE_PREFIX is the consul.fullname in helm.
// ProxyUserID: a constant set in Annotations or read from namespace when using OpenShift
// ProxyInboundPort: the service port or bind port
// ProxyOutboundPort: default transparent proxy outbound port or transparent proxy outbound listener port
// ExcludeInboundPorts: prometheus, envoy stats, expose paths, checks and excluded pod annotations
// ExcludeOutboundPorts: pod annotations
// ExcludeOutboundCIDRs: pod annotations
// ExcludeUIDs: pod annotations
func (w *MeshWebhook) iptablesConfigJSON(pod corev1.Pod, ns corev1.Namespace) (string, error) {
cfg := iptables.Config{}
if !w.EnableOpenShift {
cfg.ProxyUserID = strconv.Itoa(sidecarUserAndGroupID)
} else {
// When using OpenShift, the uid and group are saved as an annotation on the namespace
uid, err := common.GetOpenShiftUID(&ns)
if err != nil {
return "", err
}
cfg.ProxyUserID = strconv.FormatInt(uid, 10)
}
// Set the proxy's inbound port.
cfg.ProxyInboundPort = constants.ProxyDefaultInboundPort
// Set the proxy's outbound port.
cfg.ProxyOutboundPort = iptables.DefaultTProxyOutboundPort
// If metrics are enabled, get the prometheusScrapePort and exclude it from the inbound ports
enableMetrics, err := w.MetricsConfig.EnableMetrics(pod)
if err != nil {
return "", err
}
if enableMetrics {
prometheusScrapePort, err := w.MetricsConfig.PrometheusScrapePort(pod)
if err != nil {
return "", err
}
cfg.ExcludeInboundPorts = append(cfg.ExcludeInboundPorts, prometheusScrapePort)
}
// Exclude any overwritten liveness/readiness/startup ports from redirection.
overwriteProbes, err := common.ShouldOverwriteProbes(pod, w.TProxyOverwriteProbes)
if err != nil {
return "", err
}
// Exclude the port on which the proxy health check port will be configured if
// using the proxy health check for a service.
if useProxyHealthCheck(pod) {
cfg.ExcludeInboundPorts = append(cfg.ExcludeInboundPorts, strconv.Itoa(constants.ProxyDefaultHealthPort))
}
if overwriteProbes {
// We don't use the loop index because this needs to line up w.overwriteProbes(),
// which is performed after the sidecar is injected.
idx := 0
for _, container := range pod.Spec.Containers {
// skip the "consul-dataplane" container from having its probes overridden
if container.Name == sidecarContainer {
continue
}
if container.LivenessProbe != nil && container.LivenessProbe.HTTPGet != nil {
cfg.ExcludeInboundPorts = append(cfg.ExcludeInboundPorts, strconv.Itoa(exposedPathsLivenessPortsRangeStart+idx))
}
if container.ReadinessProbe != nil && container.ReadinessProbe.HTTPGet != nil {
cfg.ExcludeInboundPorts = append(cfg.ExcludeInboundPorts, strconv.Itoa(exposedPathsReadinessPortsRangeStart+idx))
}
if container.StartupProbe != nil && container.StartupProbe.HTTPGet != nil {
cfg.ExcludeInboundPorts = append(cfg.ExcludeInboundPorts, strconv.Itoa(exposedPathsStartupPortsRangeStart+idx))
}
idx++
}
}
// Inbound ports
excludeInboundPorts := splitCommaSeparatedItemsFromAnnotation(constants.AnnotationTProxyExcludeInboundPorts, pod)
cfg.ExcludeInboundPorts = append(cfg.ExcludeInboundPorts, excludeInboundPorts...)
// Outbound ports
excludeOutboundPorts := splitCommaSeparatedItemsFromAnnotation(constants.AnnotationTProxyExcludeOutboundPorts, pod)
cfg.ExcludeOutboundPorts = append(cfg.ExcludeOutboundPorts, excludeOutboundPorts...)
// Outbound CIDRs
excludeOutboundCIDRs := splitCommaSeparatedItemsFromAnnotation(constants.AnnotationTProxyExcludeOutboundCIDRs, pod)
cfg.ExcludeOutboundCIDRs = append(cfg.ExcludeOutboundCIDRs, excludeOutboundCIDRs...)
// UIDs
excludeUIDs := splitCommaSeparatedItemsFromAnnotation(constants.AnnotationTProxyExcludeUIDs, pod)
cfg.ExcludeUIDs = append(cfg.ExcludeUIDs, excludeUIDs...)
// Add init container user ID to exclude from traffic redirection.
cfg.ExcludeUIDs = append(cfg.ExcludeUIDs, strconv.Itoa(initContainersUserAndGroupID))
dnsEnabled, err := consulDNSEnabled(ns, pod, w.EnableConsulDNS, w.EnableTransparentProxy)
if err != nil {
return "", err
}
if dnsEnabled {
// If Consul DNS is enabled, we find the environment variable that has the value
// of the ClusterIP of the Consul DNS Service. constructDNSServiceHostName returns
// the name of the env variable whose value is the ClusterIP of the Consul DNS Service.
cfg.ConsulDNSIP = consulDataplaneDNSBindHost
cfg.ConsulDNSPort = consulDataplaneDNSBindPort
}
iptablesConfigJson, err := json.Marshal(&cfg)
if err != nil {
return "", fmt.Errorf("could not marshal iptables config: %w", err)
}
return string(iptablesConfigJson), nil
}
// addRedirectTrafficConfigAnnotation add the created iptables JSON config as an annotation on the provided pod.
func (w *MeshWebhook) addRedirectTrafficConfigAnnotation(pod *corev1.Pod, ns corev1.Namespace) error {
iptablesConfig, err := w.iptablesConfigJSON(*pod, ns)
if err != nil {
return err
}
pod.Annotations[constants.AnnotationRedirectTraffic] = iptablesConfig
return nil
}