Skip to content

Commit e0591e4

Browse files
Merge pull request from GHSA-284c-x8m7-9w5h
* api token fix Signed-off-by: Elena Kolevska <[email protected]> * Add released notes for 1.13.3 Signed-off-by: Artur Souza <[email protected]> --------- Signed-off-by: Elena Kolevska <[email protected]> Signed-off-by: Artur Souza <[email protected]> Co-authored-by: Elena Kolevska <[email protected]>
1 parent 3cc0fc0 commit e0591e4

File tree

17 files changed

+1114
-7
lines changed

17 files changed

+1114
-7
lines changed

docs/release_notes/v1.13.3.md

+80
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
# Dapr 1.13.3
2+
3+
This update includes bug fixes:
4+
5+
- [App API token forwarded from caller to receiving app](#app-api-token-forwarded-from-caller-to-receiving-app)
6+
- [Upgrade Go version to 1.21.9](#upgrade-go-version-to-1219)
7+
- [Placement server fails to disseminate placement tables](#placement-server-fails-to-disseminate-placement-tables)
8+
- [Restore dapr_http_server_response_count HTTP metric](#restore-dapr_http_server_response_count-http-metric)
9+
10+
## App API token forwarded from caller to receiving app
11+
12+
### Problem
13+
14+
The caller sidecar is appending the *local* app API token to the *egress* request, thereby leaking the API token protecting the local app to the foreign sidecar.
15+
16+
### Impact
17+
18+
Receiving app can have access to the calling app's API token and make unauthorized calls directly to the originating app - in case it is listening on 0.0.0.0 or an accessible IP address.
19+
20+
### Root cause
21+
22+
A pull request accidentally added this change.
23+
24+
### Solution
25+
26+
Fixed the issue and added integration tests to verify and avoid future regressions.
27+
28+
## Upgrade Go version to 1.21.9
29+
30+
### Problem
31+
32+
Go version 1.21.8 or older are impacted by CVE-2023-45288.
33+
34+
### Impact
35+
36+
See https://nvd.nist.gov/vuln/detail/CVE-2023-45288
37+
38+
### Root cause
39+
40+
See https://nvd.nist.gov/vuln/detail/CVE-2023-45288
41+
42+
### Solution
43+
44+
Update Go version used to build Dapr.
45+
46+
## Placement server fails to disseminate placement tables
47+
48+
### Problem
49+
50+
In case of an error during dissemination of placement table to a sidecar instance, the dissemination to the remaining instances do not complete. See https://github.com/dapr/dapr/issues/7031
51+
52+
### Impact
53+
54+
Sidecars can run with an old copy of the dissemination table and cannot invoke the correct Dapr sidecar for a given actor instance.
55+
56+
### Root cause
57+
58+
During shutdown, all publish calls to the application where being cancelled.
59+
60+
### Solution
61+
62+
Check the return value of performTableDissemination for errors.
63+
64+
## Restore `dapr_http_server_response_count` HTTP metric
65+
66+
### Problem
67+
68+
An existing metrics was removed without deprecation notice, affecting users that relied on it. See https://github.com/dapr/dapr/issues/7642
69+
70+
### Impact
71+
72+
Users did not have this specific metric available anymore, potentially impacting their alerts and monitoring.
73+
74+
### Root cause
75+
76+
Metric removed without deprecation notice.
77+
78+
### Solution
79+
80+
Added the metric back.

pkg/messaging/grpc_proxy.go

+6-5
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,12 @@ func (p *proxy) intercept(ctx context.Context, fullName string) (context.Context
129129
if err != nil {
130130
return ctx, nil, nil, nopTeardown, err
131131
}
132+
133+
appMetadataToken := security.GetAppToken()
134+
if appMetadataToken != "" {
135+
outCtx = metadata.AppendToOutgoingContext(outCtx, securityConsts.APITokenHeader, appMetadataToken)
136+
}
137+
132138
return outCtx, appClient.(*grpc.ClientConn), nil, nopTeardown, nil
133139
}
134140

@@ -139,11 +145,6 @@ func (p *proxy) intercept(ctx context.Context, fullName string) (context.Context
139145
outCtx = p.telemetryFn(outCtx)
140146
outCtx = metadata.AppendToOutgoingContext(outCtx, invokev1.CallerIDHeader, p.appID, invokev1.CalleeIDHeader, target.id)
141147

142-
appMetadataToken := security.GetAppToken()
143-
if appMetadataToken != "" {
144-
outCtx = metadata.AppendToOutgoingContext(outCtx, securityConsts.APITokenHeader, appMetadataToken)
145-
}
146-
147148
pt := &grpcProxy.ProxyTarget{
148149
ID: target.id,
149150
Namespace: target.namespace,

pkg/messaging/grpc_proxy_test.go

+7-2
Original file line numberDiff line numberDiff line change
@@ -188,14 +188,19 @@ func TestIntercept(t *testing.T) {
188188
}, nil
189189
})
190190

191+
t.Setenv(securityConsts.AppAPITokenEnvVar, "token1")
192+
191193
ctx := metadata.NewIncomingContext(context.TODO(), metadata.MD{diagnostics.GRPCProxyAppIDKey: []string{"a"}})
192194
proxy := p.(*proxy)
193-
_, conn, _, teardown, err := proxy.intercept(ctx, "/test")
195+
ctx, conn, _, teardown, err := proxy.intercept(ctx, "/test")
194196
defer teardown(true)
195197

196198
require.NoError(t, err)
197199
assert.NotNil(t, conn)
198200
assert.Equal(t, "a", conn.Target())
201+
202+
md, _ := metadata.FromOutgoingContext(ctx)
203+
assert.Equal(t, "token1", md[securityConsts.APITokenHeader][0])
199204
})
200205

201206
t.Run("proxy to a remote app", func(t *testing.T) {
@@ -231,7 +236,7 @@ func TestIntercept(t *testing.T) {
231236
assert.Equal(t, "b", md["a"][0])
232237
assert.Equal(t, "a", md[invokev1.CallerIDHeader][0])
233238
assert.Equal(t, "b", md[invokev1.CalleeIDHeader][0])
234-
assert.Equal(t, "token1", md[securityConsts.APITokenHeader][0])
239+
assert.NotContains(t, md, securityConsts.APITokenHeader)
235240
})
236241

237242
t.Run("access policies applied", func(t *testing.T) {

tests/integration/framework/process/daprd/options.go

+6
Original file line numberDiff line numberDiff line change
@@ -287,3 +287,9 @@ func WithSocket(t *testing.T, socket *socket.Socket) Option {
287287
"DAPR_COMPONENTS_SOCKETS_FOLDER", socket.Directory(),
288288
))
289289
}
290+
291+
func WithAppAPIToken(t *testing.T, token string) Option {
292+
return WithExecOptions(exec.WithEnvVars(t,
293+
"APP_API_TOKEN", token,
294+
))
295+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
/*
2+
Copyright 2024 The Dapr Authors
3+
Licensed under the Apache License, Version 2.0 (the "License");
4+
you may not use this file except in compliance with the License.
5+
You may obtain a copy of the License at
6+
http://www.apache.org/licenses/LICENSE-2.0
7+
Unless required by applicable law or agreed to in writing, software
8+
distributed under the License is distributed on an "AS IS" BASIS,
9+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implieh.
10+
See the License for the specific language governing permissions and
11+
limitations under the License.
12+
*/
13+
14+
package appapitoken
15+
16+
import (
17+
"context"
18+
"testing"
19+
"time"
20+
21+
"github.com/stretchr/testify/assert"
22+
"github.com/stretchr/testify/require"
23+
"google.golang.org/grpc/metadata"
24+
"google.golang.org/protobuf/types/known/anypb"
25+
26+
commonv1 "github.com/dapr/dapr/pkg/proto/common/v1"
27+
runtimev1 "github.com/dapr/dapr/pkg/proto/runtime/v1"
28+
"github.com/dapr/dapr/tests/integration/framework"
29+
"github.com/dapr/dapr/tests/integration/framework/process/daprd"
30+
"github.com/dapr/dapr/tests/integration/framework/process/grpc/app"
31+
"github.com/dapr/dapr/tests/integration/suite"
32+
testpb "github.com/dapr/dapr/tests/integration/suite/daprd/serviceinvocation/grpc/proto"
33+
)
34+
35+
func init() {
36+
suite.Register(new(remotebothtokens))
37+
}
38+
39+
type remotebothtokens struct {
40+
daprd1 *daprd.Daprd
41+
daprd2 *daprd.Daprd
42+
ch chan metadata.MD
43+
}
44+
45+
func (b *remotebothtokens) Setup(t *testing.T) []framework.Option {
46+
fn, ch := newServer()
47+
b.ch = ch
48+
app := app.New(t,
49+
app.WithRegister(fn),
50+
app.WithOnInvokeFn(func(ctx context.Context, _ *commonv1.InvokeRequest) (*commonv1.InvokeResponse, error) {
51+
md, ok := metadata.FromIncomingContext(ctx)
52+
require.True(t, ok)
53+
b.ch <- md
54+
return new(commonv1.InvokeResponse), nil
55+
}),
56+
)
57+
58+
b.daprd1 = daprd.New(t,
59+
daprd.WithAppID("app1"),
60+
daprd.WithAppProtocol("grpc"),
61+
daprd.WithAppAPIToken(t, "abc"),
62+
)
63+
64+
b.daprd2 = daprd.New(t,
65+
daprd.WithAppProtocol("grpc"),
66+
daprd.WithAppAPIToken(t, "def"),
67+
daprd.WithAppPort(app.Port(t)),
68+
)
69+
70+
return []framework.Option{
71+
framework.WithProcesses(app, b.daprd1, b.daprd2),
72+
}
73+
}
74+
75+
func (b *remotebothtokens) Run(t *testing.T, ctx context.Context) {
76+
b.daprd1.WaitUntilRunning(t, ctx)
77+
b.daprd2.WaitUntilRunning(t, ctx)
78+
79+
client := testpb.NewTestServiceClient(b.daprd1.GRPCConn(t, ctx))
80+
ctx = metadata.AppendToOutgoingContext(ctx, "dapr-app-id", b.daprd2.AppID())
81+
_, err := client.Ping(ctx, new(testpb.PingRequest))
82+
require.NoError(t, err)
83+
84+
select {
85+
case md := <-b.ch:
86+
require.Equal(t, []string{"def"}, md.Get("dapr-api-token"))
87+
case <-time.After(10 * time.Second):
88+
assert.Fail(t, "timed out waiting for metadata")
89+
}
90+
91+
dclient := b.daprd1.GRPCClient(t, ctx)
92+
_, err = dclient.InvokeService(ctx, &runtimev1.InvokeServiceRequest{
93+
Id: b.daprd2.AppID(),
94+
Message: &commonv1.InvokeRequest{
95+
Method: "helloworld",
96+
Data: new(anypb.Any),
97+
HttpExtension: &commonv1.HTTPExtension{Verb: commonv1.HTTPExtension_GET},
98+
},
99+
})
100+
require.NoError(t, err)
101+
102+
select {
103+
case md := <-b.ch:
104+
require.Equal(t, []string{"def"}, md.Get("dapr-api-token"))
105+
case <-time.After(5 * time.Second):
106+
assert.Fail(t, "timed out waiting for metadata")
107+
}
108+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
/*
2+
Copyright 2024 The Dapr Authors
3+
Licensed under the Apache License, Version 2.0 (the "License");
4+
you may not use this file except in compliance with the License.
5+
You may obtain a copy of the License at
6+
http://www.apache.org/licenses/LICENSE-2.0
7+
Unless required by applicable law or agreed to in writing, software
8+
distributed under the License is distributed on an "AS IS" BASIS,
9+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implieh.
10+
See the License for the specific language governing permissions and
11+
limitations under the License.
12+
*/
13+
14+
package appapitoken
15+
16+
import (
17+
"context"
18+
"testing"
19+
"time"
20+
21+
"github.com/stretchr/testify/assert"
22+
"github.com/stretchr/testify/require"
23+
"google.golang.org/grpc/metadata"
24+
"google.golang.org/protobuf/types/known/anypb"
25+
26+
commonv1 "github.com/dapr/dapr/pkg/proto/common/v1"
27+
runtimev1 "github.com/dapr/dapr/pkg/proto/runtime/v1"
28+
"github.com/dapr/dapr/tests/integration/framework"
29+
"github.com/dapr/dapr/tests/integration/framework/process/daprd"
30+
"github.com/dapr/dapr/tests/integration/framework/process/grpc/app"
31+
"github.com/dapr/dapr/tests/integration/suite"
32+
testpb "github.com/dapr/dapr/tests/integration/suite/daprd/serviceinvocation/grpc/proto"
33+
)
34+
35+
func init() {
36+
suite.Register(new(remotereceiverhastoken))
37+
}
38+
39+
type remotereceiverhastoken struct {
40+
daprd1 *daprd.Daprd
41+
daprd2 *daprd.Daprd
42+
ch chan metadata.MD
43+
}
44+
45+
func (r *remotereceiverhastoken) Setup(t *testing.T) []framework.Option {
46+
fn, ch := newServer()
47+
r.ch = ch
48+
app := app.New(t,
49+
app.WithRegister(fn),
50+
app.WithOnInvokeFn(func(ctx context.Context, _ *commonv1.InvokeRequest) (*commonv1.InvokeResponse, error) {
51+
md, ok := metadata.FromIncomingContext(ctx)
52+
require.True(t, ok)
53+
r.ch <- md
54+
return new(commonv1.InvokeResponse), nil
55+
}),
56+
)
57+
58+
r.daprd1 = daprd.New(t)
59+
r.daprd2 = daprd.New(t,
60+
daprd.WithAppProtocol("grpc"),
61+
daprd.WithAppAPIToken(t, "abc"),
62+
daprd.WithAppPort(app.Port(t)),
63+
)
64+
65+
return []framework.Option{
66+
framework.WithProcesses(app, r.daprd1, r.daprd2),
67+
}
68+
}
69+
70+
func (r *remotereceiverhastoken) Run(t *testing.T, ctx context.Context) {
71+
r.daprd1.WaitUntilRunning(t, ctx)
72+
r.daprd2.WaitUntilRunning(t, ctx)
73+
74+
client := testpb.NewTestServiceClient(r.daprd1.GRPCConn(t, ctx))
75+
ctx = metadata.AppendToOutgoingContext(ctx, "dapr-app-id", r.daprd2.AppID())
76+
_, err := client.Ping(ctx, new(testpb.PingRequest))
77+
require.NoError(t, err)
78+
79+
select {
80+
case md := <-r.ch:
81+
require.Equal(t, []string{"abc"}, md.Get("dapr-api-token"))
82+
case <-time.After(5 * time.Second):
83+
assert.Fail(t, "timed out waiting for metadata")
84+
}
85+
86+
dclient := r.daprd1.GRPCClient(t, ctx)
87+
_, err = dclient.InvokeService(ctx, &runtimev1.InvokeServiceRequest{
88+
Id: r.daprd2.AppID(),
89+
Message: &commonv1.InvokeRequest{
90+
Method: "helloworld",
91+
Data: new(anypb.Any),
92+
HttpExtension: &commonv1.HTTPExtension{Verb: commonv1.HTTPExtension_GET},
93+
},
94+
})
95+
require.NoError(t, err)
96+
97+
select {
98+
case md := <-r.ch:
99+
require.Equal(t, []string{"abc"}, md.Get("dapr-api-token"))
100+
case <-time.After(5 * time.Second):
101+
assert.Fail(t, "timed out waiting for metadata")
102+
}
103+
}

0 commit comments

Comments
 (0)