Skip to content

Commit

Permalink
Merge tag '1.22.8' into tetrate-release-1.22
Browse files Browse the repository at this point in the history
Istio release 1.22.8
  • Loading branch information
github-actions committed Jan 24, 2025
2 parents 424d472 + 6abd1e5 commit e305333
Show file tree
Hide file tree
Showing 30 changed files with 640 additions and 72 deletions.
2 changes: 1 addition & 1 deletion Makefile.core.mk
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ endif
export VERSION

# Base version of Istio image to use
BASE_VERSION ?= 1.22-2024-11-26T19-01-41
BASE_VERSION ?= 1.22-2024-12-17T19-01-34
ISTIO_BASE_REGISTRY ?= gcr.io/istio-release

export GO111MODULE ?= on
Expand Down
2 changes: 1 addition & 1 deletion istio.deps
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"name": "PROXY_REPO_SHA",
"repoName": "proxy",
"file": "",
"lastStableSHA": "d17e607ff67ff7b6eccbf396d370d7a2c53a5238"
"lastStableSHA": "b79502579bd44605d3ce9e1747ac3ed330beb947"
},
{
"_comment": "",
Expand Down
5 changes: 5 additions & 0 deletions pilot/pkg/model/telemetry.go
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,11 @@ func (t *Telemetries) AccessLogging(push *PushContext, proxy *Proxy, class netwo
cfgs = append(cfgs, cfg)
}

// Sort the access logs by provider name for deterministic ordering
sort.Slice(cfgs, func(i, j int) bool {
return cfgs[i].Provider.Name < cfgs[j].Provider.Name
})

t.computedLoggingConfig[key] = cfgs
return cfgs
}
Expand Down
2 changes: 0 additions & 2 deletions pilot/pkg/model/telemetry_logging_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ package model

import (
"reflect"
"sort"
"testing"

accesslog "github.com/envoyproxy/go-control-plane/envoy/config/accesslog/v3"
Expand Down Expand Up @@ -699,7 +698,6 @@ func TestAccessLogging(t *testing.T) {
}
got = append(got, p.Provider.Name)
}
sort.Strings(got)
}
if !reflect.DeepEqual(got, tt.want) {
t.Fatalf("got %v want %v", got, tt.want)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ import (
"istio.io/istio/pkg/kube/kclient/clienttest"
"istio.io/istio/pkg/kube/krt"
"istio.io/istio/pkg/network"
"istio.io/istio/pkg/ptr"
"istio.io/istio/pkg/slices"
"istio.io/istio/pkg/test"
"istio.io/istio/pkg/test/util/assert"
Expand Down Expand Up @@ -870,10 +871,10 @@ func TestAmbientIndex_Policy(t *testing.T) {
}
})
s.assertEvent(t, s.podXdsName("pod1"), s.podXdsName("pod2"), xdsConvertedPeerAuthSelector) // Matching pods receive an event
// The policy should still be added since the effective policy is STRICT
// There should be no static strict policy because the permissive override should have the strict part in-line
assert.Equal(t,
s.lookup(s.addrXdsName("127.0.0.1"))[0].Address.GetWorkload().AuthorizationPolicies,
[]string{fmt.Sprintf("istio-system/%s", staticStrictPolicyName), fmt.Sprintf("ns1/%s", model.GetAmbientPolicyConfigName(model.ConfigKey{
[]string{fmt.Sprintf("ns1/%s", model.GetAmbientPolicyConfigName(model.ConfigKey{
Kind: kind.PeerAuthentication,
Name: selectorPolicyName,
Namespace: "ns1",
Expand Down Expand Up @@ -1179,15 +1180,88 @@ func TestRBACConvert(t *testing.T) {
},
Spec: *((pol[0].Spec).(*auth.AuthorizationPolicy)), //nolint: govet
})
case gvk.PeerAuthentication:
o = convertPeerAuthentication(systemNS, &clientsecurityv1beta1.PeerAuthentication{
TypeMeta: metav1.TypeMeta{},
ObjectMeta: metav1.ObjectMeta{
Name: pol[0].Name,
Namespace: pol[0].Namespace,
},
Spec: *((pol[0].Spec).(*auth.PeerAuthentication)), //nolint: govet
})
case gvk.PeerAuthentication: // we assume all crds in the same file are of the same type
var rootCfg, nsCfg, workloadCfg *config.Config
if len(pol) > 1 {
for _, p := range pol {
switch p.Namespace {
case systemNS:
if p.Spec.(*auth.PeerAuthentication).GetSelector() != nil {
t.Fatalf("unexpected selector in mesh-level policy %v", p)
}
if rootCfg == nil || p.GetCreationTimestamp().Before(rootCfg.GetCreationTimestamp()) {
rootCfg = ptr.Of(p)
}
default:
spec := p.Spec.(*auth.PeerAuthentication)
if spec.GetSelector() != nil && workloadCfg != nil && workloadCfg.Spec.(*auth.PeerAuthentication).GetSelector() != nil {
t.Fatalf("multiple workload-level policies %v and %v", p, workloadCfg)
}

if spec.GetSelector() != nil {
// Workload policy
workloadCfg = ptr.Of(p)
} else if nsCfg == nil || p.GetCreationTimestamp().Before(nsCfg.GetCreationTimestamp()) {
// Namespace policy
nsCfg = ptr.Of(p)
}
}
}
}

// Simple case
if len(pol) == 1 {
o = convertPeerAuthentication(systemNS, &clientsecurityv1beta1.PeerAuthentication{
TypeMeta: metav1.TypeMeta{},
ObjectMeta: metav1.ObjectMeta{
Name: pol[0].Name,
Namespace: pol[0].Namespace,
},
Spec: *((pol[0].Spec).(*auth.PeerAuthentication)), //nolint: govet
}, nil, nil)
} else {
var workloadPA, nsPA, rootPA *clientsecurityv1beta1.PeerAuthentication
if workloadCfg != nil {
workloadPA = &clientsecurityv1beta1.PeerAuthentication{
TypeMeta: metav1.TypeMeta{},
ObjectMeta: metav1.ObjectMeta{
Name: workloadCfg.Name,
Namespace: workloadCfg.Namespace,
},
Spec: *((workloadCfg.Spec).(*auth.PeerAuthentication)), //nolint: govet
}
}
if nsCfg != nil {
nsPA = &clientsecurityv1beta1.PeerAuthentication{
TypeMeta: metav1.TypeMeta{},
ObjectMeta: metav1.ObjectMeta{
Name: nsCfg.Name,
Namespace: nsCfg.Namespace,
},
Spec: *((nsCfg.Spec).(*auth.PeerAuthentication)), //nolint: govet
}
}

if rootCfg != nil {
rootPA = &clientsecurityv1beta1.PeerAuthentication{
TypeMeta: metav1.TypeMeta{},
ObjectMeta: metav1.ObjectMeta{
Name: rootCfg.Name,
Namespace: rootCfg.Namespace,
},
Spec: *((rootCfg.Spec).(*auth.PeerAuthentication)), //nolint: govet
}
}

if workloadPA == nil {
// We have a namespace policy and a root policy; send the NS policy as the workload policy
// It won't get far anyway since this convert function returns nil for non-workload policies
workloadPA = nsPA
nsPA = nil
}

o = convertPeerAuthentication(systemNS, workloadPA, nsPA, rootPA)
}
default:
t.Fatalf("unknown kind %v", pol[0].GroupVersionKind)
}
Expand Down
128 changes: 89 additions & 39 deletions pilot/pkg/serviceregistry/kube/controller/ambient/authorization.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ import (
"istio.io/istio/pilot/pkg/model"
"istio.io/istio/pkg/config/schema/kind"
"istio.io/istio/pkg/log"
"istio.io/istio/pkg/maps"
"istio.io/istio/pkg/slices"
"istio.io/istio/pkg/util/sets"
"istio.io/istio/pkg/workloadapi/security"
)
Expand Down Expand Up @@ -56,8 +58,18 @@ func (a *index) Policies(requested sets.Set[model.ConfigKey]) []model.WorkloadAu
return res
}

func getOldestPeerAuthn(policies []*securityclient.PeerAuthentication) *securityclient.PeerAuthentication {
var oldest *securityclient.PeerAuthentication
for _, pol := range policies {
if oldest == nil || pol.CreationTimestamp.Before(&oldest.CreationTimestamp) {
oldest = pol
}
}
return oldest
}

// convertedSelectorPeerAuthentications returns a list of keys corresponding to one or both of:
// [static STRICT policy, port-level STRICT policy] based on the effective PeerAuthentication policy
// [static STRICT policy, port-level (potentially merged) STRICT policy] based on the effective PeerAuthentication policy
func convertedSelectorPeerAuthentications(rootNamespace string, configs []*securityclient.PeerAuthentication) []string {
var meshCfg, namespaceCfg, workloadCfg *securityclient.PeerAuthentication
for _, cfg := range configs {
Expand Down Expand Up @@ -92,9 +104,7 @@ func convertedSelectorPeerAuthentications(rootNamespace string, configs []*secur

// Process in mesh, namespace, workload order to resolve inheritance (UNSET)
if meshCfg != nil {
if !isMtlsModeUnset(meshCfg.Spec.Mtls) {
isEffectiveStrictPolicy = isMtlsModeStrict(meshCfg.Spec.Mtls)
}
isEffectiveStrictPolicy = isMtlsModeStrict(meshCfg.Spec.Mtls)
}

if namespaceCfg != nil {
Expand All @@ -109,12 +119,10 @@ func convertedSelectorPeerAuthentications(rootNamespace string, configs []*secur

workloadSpec := &workloadCfg.Spec

// Regardless of if we have port-level overrides, if the workload policy is STRICT, then we need to reference our static STRICT policy
if isMtlsModeStrict(workloadSpec.Mtls) {
isEffectiveStrictPolicy = true
}

// Regardless of if we have port-level overrides, if the workload policy is PERMISSIVE or DISABLE, then we shouldn't send our static STRICT policy
if isMtlsModePermissive(workloadSpec.Mtls) || isMtlsModeDisable(workloadSpec.Mtls) {
isEffectiveStrictPolicy = false
}
Expand Down Expand Up @@ -174,6 +182,8 @@ func convertedSelectorPeerAuthentications(rootNamespace string, configs []*secur
Kind: kind.PeerAuthentication,
Namespace: workloadCfg.Namespace,
})
// We DON'T want to send the static STRICT policy since the merged form of this policy will include the default STRICT mode
isEffectiveStrictPolicy = false
}
} else {
// Permissive mesh or namespace policy
Expand Down Expand Up @@ -215,15 +225,9 @@ func effectivePeerAuthenticationKeys(rootNamespace string, isEffectiveStringPoli
return sets.SortedList(res)
}

// convertPeerAuthentication converts a PeerAuthentication to an L4 authorization policy (i.e. security.Authorization) iff
// 1. the PeerAuthentication has a workload selector
// 2. The PeerAuthentication is NOT in the root namespace
// 3. There is a portLevelMtls policy (technically implied by 1)
// 4. If the top-level mode is PERMISSIVE or DISABLE, there is at least one portLevelMtls policy with mode STRICT
//
// STRICT policies that don't have portLevelMtls will be
// handled when the Workload xDS resource is pushed (a static STRICT-equivalent policy will always be pushed)
func convertPeerAuthentication(rootNamespace string, cfg *securityclient.PeerAuthentication) *security.Authorization {
// convertPeerAuthentication converts a PeerAuthentication to an L4 authorization policy (i.e. security.Authorization)
// taking into account the top level policies (and merging if necessary)
func convertPeerAuthentication(rootNamespace string, cfg, nsCfg, rootCfg *securityclient.PeerAuthentication) *security.Authorization {
pa := &cfg.Spec

mode := pa.GetMtls().GetMode()
Expand All @@ -237,6 +241,7 @@ func convertPeerAuthentication(rootNamespace string, cfg *securityclient.PeerAut

action := security.Action_DENY
var rules []*security.Rules
var groups []*security.Group

if mode == v1beta1.PeerAuthentication_MutualTLS_STRICT {
rules = append(rules, &security.Rules{
Expand All @@ -257,47 +262,60 @@ func convertPeerAuthentication(rootNamespace string, cfg *securityclient.PeerAut
// Note that this doesn't actually attach the policy to any workload; it just makes it available
// to ztunnel in case a workload needs it.
foundNonStrictPortmTLS := false
for port, mtls := range pa.PortLevelMtls {
keys := slices.Sort(maps.Keys(pa.PortLevelMtls))
for _, port := range keys {
mtls := pa.PortLevelMtls[port]
switch portMtlsMode := mtls.GetMode(); {
case portMtlsMode == v1beta1.PeerAuthentication_MutualTLS_STRICT:
rules = append(rules, &security.Rules{
Matches: []*security.Match{
// If either:
// 1. The workload-level policy is STRICT
// 2. The workload level policy is nil/unset and the namespace-level policy is STRICT
// 3. The workload level policy is nil/unset and the namespace-level policy is nil/unset and the mesh-level policy is STRICT
// then we don't need to add a rule for this STRICT port since it will be enforced by the parent policy
if isMtlsModeStrict(pa.GetMtls()) || // #1
(isMtlsModeUnset(pa.GetMtls()) && // First condition for #2 and #3
(nsCfg != nil && isMtlsModeStrict(nsCfg.Spec.Mtls)) || // #2
// #3
((nsCfg == nil || isMtlsModeUnset(nsCfg.Spec.Mtls)) && rootCfg != nil && isMtlsModeStrict(rootCfg.Spec.Mtls))) {
log.Debugf("skipping port %s/%s for PeerAuthentication %s/%s for ambient since the parent mTLS mode is %s",
port, portMtlsMode, cfg.Namespace, cfg.Name, mode)
continue
}
// Groups are OR'd so we need to create one for each STRICT workload port
groups = append(groups, &security.Group{
Rules: []*security.Rules{
{
NotPrincipals: []*security.StringMatch{
Matches: []*security.Match{
{
MatchType: &security.StringMatch_Presence{},
NotPrincipals: []*security.StringMatch{
{
MatchType: &security.StringMatch_Presence{},
},
},
DestinationPorts: []uint32{port},
},
},
DestinationPorts: []uint32{port},
},
},
})
case portMtlsMode == v1beta1.PeerAuthentication_MutualTLS_PERMISSIVE:
case portMtlsMode == v1beta1.PeerAuthentication_MutualTLS_PERMISSIVE, portMtlsMode == v1beta1.PeerAuthentication_MutualTLS_DISABLE:
// Check top-level mode
if mode == v1beta1.PeerAuthentication_MutualTLS_PERMISSIVE || mode == v1beta1.PeerAuthentication_MutualTLS_DISABLE {
// we don't care; log and continue
log.Debugf("skipping port %s/%s for PeerAuthentication %s/%s for ambient since the parent mTLS mode is %s",
port, portMtlsMode, cfg.Namespace, cfg.Name, mode)
continue
}
foundNonStrictPortmTLS = true

// If the top level policy is STRICT, we need to add a rule for the port that exempts it from the deny policy
rules = append(rules, &security.Rules{
Matches: []*security.Match{
{
NotDestinationPorts: []uint32{port}, // if the incoming connection does not match this port, deny (notice there's no principals requirement)
},
},
})
case portMtlsMode == v1beta1.PeerAuthentication_MutualTLS_DISABLE:
// Check top-level mode
if mode == v1beta1.PeerAuthentication_MutualTLS_PERMISSIVE || mode == v1beta1.PeerAuthentication_MutualTLS_DISABLE {
if mode == v1beta1.PeerAuthentication_MutualTLS_UNSET && ((nsCfg != nil && !isMtlsModeStrict(nsCfg.Spec.Mtls)) ||
(nsCfg == nil && rootCfg != nil && !isMtlsModeStrict(rootCfg.Spec.Mtls)) ||
(nsCfg == nil && rootCfg == nil)) {
// we don't care; log and continue
log.Debugf("skipping port %s/%s for PeerAuthentication %s/%s for ambient since the parent mTLS mode is %s",
port, portMtlsMode, cfg.Namespace, cfg.Name, mode)
log.Debugf("skipping port %s/%s for PeerAuthentication %s/%s for ambient since it's not STRICT and the effective policy is not STRICT",
port, portMtlsMode, cfg.Namespace, cfg.Name)
continue
}

foundNonStrictPortmTLS = true

// If the top level policy is STRICT, we need to add a rule for the port that exempts it from the deny policy
Expand All @@ -319,11 +337,43 @@ func convertPeerAuthentication(rootNamespace string, cfg *securityclient.PeerAut
return nil
}

if len(rules) == 0 {
// we never added any rules; return
if len(rules) == 0 && len(groups) == 0 {
// we never added any rules or groups; return
return nil
}

// We only need to merge if the effective policy is STRICT, the workload policy's mode is unstrict, and we have a non-strict port level policy
var shouldMergeStrict bool
// Merge if there's a STRICT root policy and the namespace policy is nil, UNSET or STRICT
if rootCfg != nil && isMtlsModeStrict(rootCfg.Spec.Mtls) && (nsCfg == nil || isMtlsModeUnset(nsCfg.Spec.Mtls) || isMtlsModeStrict(nsCfg.Spec.Mtls)) {
shouldMergeStrict = true
} else if nsCfg != nil && isMtlsModeStrict(nsCfg.Spec.Mtls) { // Merge if there's a STRICT namespace policy
shouldMergeStrict = true
}

// If the effective policy (namespace or mesh) is STRICT and we have a non-strict port level policy,
// we need to merge that strictness into the workload policy so that the static strict policy can be elided
// from the workload's policy list.
if shouldMergeStrict && foundNonStrictPortmTLS {
rules = append(rules, &security.Rules{
Matches: []*security.Match{
{
NotPrincipals: []*security.StringMatch{
{
MatchType: &security.StringMatch_Presence{},
},
},
},
},
})
}

if len(rules) > 0 {
groups = append(groups, &security.Group{
Rules: rules,
})
}

opol := &security.Authorization{
Name: model.GetAmbientPolicyConfigName(model.ConfigKey{
Name: cfg.Name,
Expand All @@ -333,7 +383,7 @@ func convertPeerAuthentication(rootNamespace string, cfg *securityclient.PeerAut
Namespace: cfg.Namespace,
Scope: scope,
Action: action,
Groups: []*security.Group{{Rules: rules}},
Groups: groups,
}

return opol
Expand Down
Loading

0 comments on commit e305333

Please sign in to comment.