Skip to content

Commit

Permalink
Provide peer Identities via the Destination API (linkerd#2537)
Browse files Browse the repository at this point in the history
This change reintroduces identity hinting to the destination service.
The Get endpoint includes identities for pods that are injected with an
identity-mode of "default" and have the same linkerd control plane.

A `serviceaccount` label is now also added to destination response
metadata so that it's accessible in prometheus and tap.
  • Loading branch information
olix0r authored Mar 22, 2019
1 parent 34ea302 commit da03307
Show file tree
Hide file tree
Showing 16 changed files with 206 additions and 58 deletions.
3 changes: 3 additions & 0 deletions chart/templates/controller.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,9 @@ spec:
containerPort: 8086
- name: admin-http
containerPort: 9996
volumeMounts:
- name: config
mountPath: /var/run/linkerd/config
image: {{.Values.ControllerImage}}
imagePullPolicy: {{.Values.ImagePullPolicy}}
args:
Expand Down
3 changes: 3 additions & 0 deletions cli/cmd/testdata/install_default.golden
Original file line number Diff line number Diff line change
Expand Up @@ -416,6 +416,9 @@ spec:
resources: {}
securityContext:
runAsUser: 2103
volumeMounts:
- mountPath: /var/run/linkerd/config
name: config
- args:
- tap
- -controller-namespace=linkerd
Expand Down
3 changes: 3 additions & 0 deletions cli/cmd/testdata/install_ha_output.golden
Original file line number Diff line number Diff line change
Expand Up @@ -428,6 +428,9 @@ spec:
memory: 50Mi
securityContext:
runAsUser: 2103
volumeMounts:
- mountPath: /var/run/linkerd/config
name: config
- args:
- tap
- -controller-namespace=linkerd
Expand Down
3 changes: 3 additions & 0 deletions cli/cmd/testdata/install_ha_with_overrides_output.golden
Original file line number Diff line number Diff line change
Expand Up @@ -428,6 +428,9 @@ spec:
memory: 50Mi
securityContext:
runAsUser: 2103
volumeMounts:
- mountPath: /var/run/linkerd/config
name: config
- args:
- tap
- -controller-namespace=linkerd
Expand Down
3 changes: 3 additions & 0 deletions cli/cmd/testdata/install_no_init_container.golden
Original file line number Diff line number Diff line change
Expand Up @@ -392,6 +392,9 @@ spec:
resources: {}
securityContext:
runAsUser: 2103
volumeMounts:
- mountPath: /var/run/linkerd/config
name: config
- args:
- tap
- -controller-namespace=linkerd
Expand Down
3 changes: 3 additions & 0 deletions cli/cmd/testdata/install_no_init_container_auto_inject.golden
Original file line number Diff line number Diff line change
Expand Up @@ -394,6 +394,9 @@ spec:
resources: {}
securityContext:
runAsUser: 2103
volumeMounts:
- mountPath: /var/run/linkerd/config
name: config
- args:
- tap
- -controller-namespace=linkerd
Expand Down
3 changes: 3 additions & 0 deletions cli/cmd/testdata/install_output.golden
Original file line number Diff line number Diff line change
Expand Up @@ -384,6 +384,9 @@ spec:
resources: {}
securityContext:
runAsUser: 2103
volumeMounts:
- mountPath: /var/run/linkerd/config
name: config
- args:
- tap
- -controller-namespace=Namespace
Expand Down
56 changes: 37 additions & 19 deletions controller/api/destination/endpoint_listener.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,8 @@ func diffUpdateAddresses(oldAddrs, newAddrs []*updateAddress) ([]*updateAddress,

// implements the endpointUpdateListener interface
type endpointListener struct {
controllerNS string
controllerNS,
identityTrustDomain string
stream pb.Destination_GetServer
ownerKindAndName ownerKindAndNameFn
labels map[string]string
Expand All @@ -107,15 +108,16 @@ func newEndpointListener(
stream pb.Destination_GetServer,
ownerKindAndName ownerKindAndNameFn,
enableH2Upgrade bool,
controllerNS string,
controllerNS, identityTrustDomain string,
) *endpointListener {
return &endpointListener{
controllerNS: controllerNS,
stream: stream,
ownerKindAndName: ownerKindAndName,
labels: make(map[string]string),
enableH2Upgrade: enableH2Upgrade,
stopCh: make(chan struct{}),
controllerNS: controllerNS,
identityTrustDomain: identityTrustDomain,
stream: stream,
ownerKindAndName: ownerKindAndName,
labels: make(map[string]string),
enableH2Upgrade: enableH2Upgrade,
stopCh: make(chan struct{}),
log: log.WithFields(log.Fields{
"component": "endpoint-listener",
}),
Expand Down Expand Up @@ -213,18 +215,14 @@ func (l *endpointListener) toWeightedAddr(address *updateAddress) *pb.WeightedAd
}
}

// TODO: restore TLS identities
//nolint
func (l *endpointListener) getAddrMetadata(pod *corev1.Pod) (map[string]string, *pb.ProtocolHint, *pb.TlsIdentity) {
controllerNS := pod.Labels[pkgK8s.ControllerNSLabel]
ownerKind, ownerName := l.ownerKindAndName(pod)
labels := pkgK8s.GetPodLabels(ownerKind, ownerName, pod)

// If the pod is controlled by us, then it can be hinted that this destination
// knows H2 (and handles our orig-proto translation). Note that this check
// does not verify that the pod's control plane matches the control plane
// where the destination service is running; all pods injected for all control
// planes are considered valid for providing the H2 hint.
sa, ns := pkgK8s.GetServiceAccountAndNS(pod)
ok, on := l.ownerKindAndName(pod)
labels := pkgK8s.GetPodLabels(ok, on, pod)

// If the pod is controlled by any Linkerd control plane, then it can be hinted
// that this destination knows H2 (and handles our orig-proto translation).
var hint *pb.ProtocolHint
if l.enableH2Upgrade && controllerNS != "" {
hint = &pb.ProtocolHint{
Expand All @@ -234,5 +232,25 @@ func (l *endpointListener) getAddrMetadata(pod *corev1.Pod) (map[string]string,
}
}

return labels, hint, nil
// If the pod is controlled by the same Linkerd control plane, then it can
// participate in identity with peers.
//
// TODO this should be relaxed to match a trust domain annotation so that
// multiple meshes can participate in identity if they share trust roots.
var identity *pb.TlsIdentity
if l.identityTrustDomain != "" &&
controllerNS == l.controllerNS &&
pod.Annotations[pkgK8s.IdentityModeAnnotation] == pkgK8s.IdentityModeDefault {

id := fmt.Sprintf("%s.%s.serviceaccount.identity.%s.%s", sa, ns, controllerNS, l.identityTrustDomain)
identity = &pb.TlsIdentity{
Strategy: &pb.TlsIdentity_DnsLikeIdentity_{
DnsLikeIdentity: &pb.TlsIdentity_DnsLikeIdentity{
Name: id,
},
},
}
}

return labels, hint, identity
}
94 changes: 76 additions & 18 deletions controller/api/destination/endpoint_listener_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,7 @@ func TestEndpointListener(t *testing.T) {
listener := newEndpointListener(
mockGetServer,
defaultOwnerKindAndName,
false,
"linkerd",
false, "linkerd", "",
)

listener.Update(add, remove)
Expand All @@ -88,8 +87,7 @@ func TestEndpointListener(t *testing.T) {
listener := newEndpointListener(
mockGetServer,
defaultOwnerKindAndName,
false,
"linkerd",
false, "linkerd", "",
)

listener.Update(add, remove)
Expand Down Expand Up @@ -129,8 +127,7 @@ func TestEndpointListener(t *testing.T) {
listener := newEndpointListener(
mockGetServer,
defaultOwnerKindAndName,
false,
"linkerd",
false, "linkerd", "",
)

completed := make(chan bool)
Expand All @@ -153,6 +150,7 @@ func TestEndpointListener(t *testing.T) {
expectedPodName := pod1.Name
expectedNamespace := thisNS
expectedReplicationControllerName := "rc-name"
expectedServiceAccountName := "serviceaccount-name"

podForAddedAddress1 := &corev1.Pod{
ObjectMeta: metav1.ObjectMeta{
Expand All @@ -162,6 +160,9 @@ func TestEndpointListener(t *testing.T) {
Status: corev1.PodStatus{
Phase: corev1.PodRunning,
},
Spec: corev1.PodSpec{
ServiceAccountName: expectedServiceAccountName,
},
}

ownerKindAndName := func(pod *corev1.Pod) (string, string) {
Expand All @@ -172,8 +173,7 @@ func TestEndpointListener(t *testing.T) {
listener := newEndpointListener(
mockGetServer,
ownerKindAndName,
false,
"linkerd",
false, "linkerd", "",
)
listener.labels = map[string]string{
"service": expectedServiceName,
Expand All @@ -195,26 +195,28 @@ func TestEndpointListener(t *testing.T) {
expectedAddedAddress1MetricLabels := map[string]string{
"pod": expectedPodName,
"replicationcontroller": expectedReplicationControllerName,
"serviceaccount": expectedServiceAccountName,
}
if !reflect.DeepEqual(actualAddedAddress1MetricLabels, expectedAddedAddress1MetricLabels) {
t.Fatalf("Expected global metric labels sent to be [%v] but was [%v]", expectedAddedAddress1MetricLabels, actualAddedAddress1MetricLabels)
}
})

t.Run("Sends TlsIdentity when enabled", func(t *testing.T) {
t.Skip("TLS is currently disabled")
expectedPodName := pod1.Name
expectedPodNamespace := thisNS
expectedControllerNamespace := "linkerd-namespace"
expectedPodDeployment := podDeployment
//expectedTLSIdentity := nil
expectedTLSIdentity := &pb.TlsIdentity_DnsLikeIdentity{
Name: "this-serviceaccount.this-namespace.serviceaccount.identity.linkerd-namespace.trust.domain",
}

podForAddedAddress1 := &corev1.Pod{
ObjectMeta: metav1.ObjectMeta{
Name: expectedPodName,
Namespace: expectedPodNamespace,
Annotations: map[string]string{
pkgK8s.IdentityModeAnnotation: "FIXME",
pkgK8s.IdentityModeAnnotation: pkgK8s.IdentityModeDefault,
},
Labels: map[string]string{
pkgK8s.ControllerNSLabel: expectedControllerNamespace,
Expand All @@ -224,6 +226,9 @@ func TestEndpointListener(t *testing.T) {
Status: corev1.PodStatus{
Phase: corev1.PodRunning,
},
Spec: corev1.PodSpec{
ServiceAccountName: "this-serviceaccount",
},
}

ownerKindAndName := func(pod *corev1.Pod) (string, string) {
Expand All @@ -236,6 +241,7 @@ func TestEndpointListener(t *testing.T) {
ownerKindAndName,
false,
expectedControllerNamespace,
"trust.domain",
)

add := []*updateAddress{
Expand All @@ -248,14 +254,64 @@ func TestEndpointListener(t *testing.T) {
t.Fatalf("Expected [1] address returned, got %v", addrs)
}

// actualTLSIdentity := addrs[0].GetTlsIdentity().GetK8SPodIdentity()
// if !reflect.DeepEqual(actualTLSIdentity, expectedTLSIdentity) {
// t.Fatalf("Expected TlsIdentity to be [%v] but was [%v]", expectedTLSIdentity, actualTLSIdentity)
// }
actualTLSIdentity := addrs[0].GetTlsIdentity().GetDnsLikeIdentity()
if !reflect.DeepEqual(actualTLSIdentity, expectedTLSIdentity) {
t.Fatalf("Expected TlsIdentity to be [%v] but was [%v]", expectedTLSIdentity, actualTLSIdentity)
}
})

t.Run("Does not send TlsIdentity for non-default identity-modes", func(t *testing.T) {
expectedPodName := "pod1"
expectedPodNamespace := thisNS
expectedControllerNamespace := "other-linkerd-namespace"
expectedPodDeployment := podDeployment

podForAddedAddress1 := &v1.Pod{
ObjectMeta: metav1.ObjectMeta{
Name: expectedPodName,
Namespace: expectedPodNamespace,
Annotations: map[string]string{
pkgK8s.IdentityModeAnnotation: "optional",
},
Labels: map[string]string{
pkgK8s.ControllerNSLabel: expectedControllerNamespace,
pkgK8s.ProxyDeploymentLabel: expectedPodDeployment,
},
},
Status: v1.PodStatus{
Phase: v1.PodRunning,
},
}

ownerKindAndName := func(pod *v1.Pod) (string, string) {
return deploymentKind, expectedPodDeployment
}

mockGetServer := &mockDestinationGetServer{updatesReceived: []*pb.Update{}}
listener := newEndpointListener(
mockGetServer,
ownerKindAndName,
false,
expectedControllerNamespace,
"trust.domain",
)

add := []*updateAddress{
{address: addedAddress1, pod: podForAddedAddress1},
}
listener.Update(add, nil)

addrs := mockGetServer.updatesReceived[0].GetAdd().GetAddrs()
if len(addrs) != 1 {
t.Fatalf("Expected [1] address returned, got %v", addrs)
}

if addrs[0].TlsIdentity != nil {
t.Fatalf("Expected no TlsIdentity to be sent, but got [%v]", addrs[0].TlsIdentity)
}
})

t.Run("Does not send TlsIdentity for other meshes", func(t *testing.T) {
t.Skip("TLS is currently disabled")
expectedPodName := "pod1"
expectedPodNamespace := thisNS
expectedControllerNamespace := "other-linkerd-namespace"
Expand All @@ -266,7 +322,7 @@ func TestEndpointListener(t *testing.T) {
Name: expectedPodName,
Namespace: expectedPodNamespace,
Annotations: map[string]string{
pkgK8s.IdentityModeAnnotation: "FIXME",
pkgK8s.IdentityModeAnnotation: pkgK8s.IdentityModeDefault,
},
Labels: map[string]string{
pkgK8s.ControllerNSLabel: expectedControllerNamespace,
Expand All @@ -288,6 +344,7 @@ func TestEndpointListener(t *testing.T) {
ownerKindAndName,
false,
"linkerd-namespace",
"trust.domain",
)

add := []*updateAddress{
Expand Down Expand Up @@ -334,7 +391,8 @@ func TestEndpointListener(t *testing.T) {
mockGetServer,
ownerKindAndName,
false,
"linkerd",
expectedControllerNamespace,
"",
)

add := []*updateAddress{
Expand Down
Loading

0 comments on commit da03307

Please sign in to comment.