Skip to content

Commit ad864dd

Browse files
committed
fix: Ensure function principals are named.
1 parent 1c32c26 commit ad864dd

File tree

7 files changed

+125
-54
lines changed

7 files changed

+125
-54
lines changed

pkg/codeconfig/codeconfig.go

Lines changed: 13 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -218,8 +218,15 @@ func (c *codeConfig) apiSpec(api string) (*openapi3.T, error) {
218218
// collectOne - Collects information about a function for a nitric stack
219219
// handler - the specific handler for the application
220220
func (c *codeConfig) collectOne(handler string) error {
221-
fun := NewFunction()
222-
srv := NewServer(fun)
221+
rt, err := runtime.NewRunTimeFromHandler(handler)
222+
if err != nil {
223+
return errors.WithMessage(err, "error getting the runtime from handler "+handler)
224+
}
225+
226+
name := rt.ContainerName()
227+
fun := NewFunction(name)
228+
229+
srv := NewServer(name, fun)
223230
grpcSrv := grpc.NewServer()
224231

225232
v1.RegisterResourceServiceServer(grpcSrv, srv)
@@ -246,11 +253,6 @@ func (c *codeConfig) collectOne(handler string) error {
246253
return errors.WithMessage(err, "error discovering container engine")
247254
}
248255

249-
rt, err := runtime.NewRunTimeFromHandler(handler)
250-
if err != nil {
251-
return errors.WithMessage(err, "error getting the runtime from handler "+handler)
252-
}
253-
254256
opts, err := rt.LaunchOptsForFunctionCollect(c.initialStack.Dir)
255257
if err != nil {
256258
return err
@@ -344,11 +346,6 @@ func (c *codeConfig) ToStack() (*stack.Stack, error) {
344346

345347
errs := utils.NewErrorList()
346348
for handler, f := range c.functions {
347-
rt, err := runtime.NewRunTimeFromHandler(handler)
348-
if err != nil {
349-
return nil, err
350-
}
351-
352349
topicTriggers := make([]string, 0, len(f.subscriptions)+len(f.schedules))
353350

354351
for k := range f.apis {
@@ -433,14 +430,14 @@ func (c *codeConfig) ToStack() (*stack.Stack, error) {
433430
}
434431
}
435432

436-
f, ok := s.Functions[rt.ContainerName()]
433+
fun, ok := s.Functions[f.name]
437434
if !ok {
438-
f = stack.FunctionFromHandler(handler, s.Dir)
435+
fun = stack.FunctionFromHandler(handler, s.Dir)
439436
}
440-
f.ComputeUnit.Triggers = stack.Triggers{
437+
fun.ComputeUnit.Triggers = stack.Triggers{
441438
Topics: topicTriggers,
442439
}
443-
s.Functions[rt.ContainerName()] = f
440+
s.Functions[f.name] = fun
444441
}
445442

446443
return s, errs.Aggregate()

pkg/codeconfig/function.go

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ func (a *Api) AddWorker(worker *pb.ApiWorker) error {
8181

8282
// FunctionDependencies - Stores information about a Nitric Function, and it's dependencies
8383
type FunctionDependencies struct {
84+
name string
8485
apis map[string]*Api
8586
subscriptions map[string]*pb.SubscriptionWorker
8687
schedules map[string]*pb.ScheduleWorker
@@ -96,6 +97,13 @@ type FunctionDependencies struct {
9697
func (a *FunctionDependencies) AddPolicy(p *pb.PolicyResource) {
9798
a.lock.Lock()
9899
defer a.lock.Unlock()
100+
for _, p := range p.Principals {
101+
// If provided a blank function principal assume its for this function
102+
if p.Type == pb.ResourceType_Function && p.Name == "" {
103+
p.Name = a.name
104+
}
105+
}
106+
99107
a.policies = append(a.policies, p)
100108
}
101109

@@ -167,8 +175,9 @@ func (a *FunctionDependencies) AddQueue(name string, q *pb.QueueResource) {
167175
}
168176

169177
// NewFunction - creates a new Nitric Function, ready to register handlers and dependencies.
170-
func NewFunction() *FunctionDependencies {
178+
func NewFunction(name string) *FunctionDependencies {
171179
return &FunctionDependencies{
180+
name: name,
172181
apis: make(map[string]*Api),
173182
subscriptions: make(map[string]*pb.SubscriptionWorker),
174183
schedules: make(map[string]*pb.ScheduleWorker),

pkg/codeconfig/server.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import (
2626
)
2727

2828
type Server struct {
29+
name string
2930
function *FunctionDependencies
3031
pb.UnimplementedFaasServiceServer
3132
pb.UnimplementedResourceServiceServer
@@ -84,8 +85,9 @@ func (s *Server) Declare(ctx context.Context, req *pb.ResourceDeclareRequest) (*
8485
}
8586

8687
// NewServer - Creates a new deployment server
87-
func NewServer(function *FunctionDependencies) *Server {
88+
func NewServer(name string, function *FunctionDependencies) *Server {
8889
return &Server{
90+
name: name,
8991
function: function,
9092
}
9193
}

pkg/provider/pulumi/aws/aws.go

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,12 @@ func (a *awsProvider) Deploy(ctx *pulumi.Context) error {
120120

121121
topics := map[string]*sns.Topic{}
122122
for k := range a.s.Topics {
123-
topics[k], err = sns.NewTopic(ctx, k, &sns.TopicArgs{Tags: commonTags(ctx, k)})
123+
topics[k], err = sns.NewTopic(ctx, k, &sns.TopicArgs{
124+
// FIXME: Autonaming of topics disabled until improvements to
125+
// nitric topic name discovery is made for SNS topics.
126+
Name: pulumi.StringPtr(k),
127+
Tags: commonTags(ctx, k),
128+
})
124129
if err != nil {
125130
return errors.WithMessage(err, "sns topic "+k)
126131
}
@@ -146,8 +151,9 @@ func (a *awsProvider) Deploy(ctx *pulumi.Context) error {
146151
}
147152
}
148153

154+
collections := map[string]*dynamodb.Table{}
149155
for k := range a.s.Collections {
150-
_, err = dynamodb.NewTable(ctx, "mytable", &dynamodb.TableArgs{
156+
collections[k], err = dynamodb.NewTable(ctx, k, &dynamodb.TableArgs{
151157
Attributes: dynamodb.TableAttributeArray{
152158
&dynamodb.TableAttributeArgs{
153159
Name: pulumi.String("_pk"),
@@ -243,15 +249,18 @@ func (a *awsProvider) Deploy(ctx *pulumi.Context) error {
243249
return err
244250
}
245251

246-
newPolicy(ctx, policyName, &PolicyArgs{
252+
if _, err := newPolicy(ctx, policyName, &PolicyArgs{
247253
Policy: p,
248254
Resources: &StackResources{
249-
Topics: topics,
250-
Queues: queues,
251-
Buckets: buckets,
255+
Topics: topics,
256+
Queues: queues,
257+
Buckets: buckets,
258+
Collections: collections,
252259
},
253260
Principals: principalMap,
254-
})
261+
}); err != nil {
262+
return err
263+
}
255264
}
256265

257266
return nil

pkg/provider/pulumi/aws/lambda.go

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -83,13 +83,19 @@ func newLambda(ctx *pulumi.Context, name string, args *LambdaArgs, opts ...pulum
8383
return nil, err
8484
}
8585

86+
// Add resource list permissions
87+
// Currently the membrane will use list operations
8688
tmpJSON, err = json.Marshal(map[string]interface{}{
8789
"Version": "2012-10-17",
8890
"Statement": []map[string]interface{}{
8991
{
9092
"Action": []string{
91-
"sns:ConfirmSubscription",
92-
"sns:Unsubscribe",
93+
// "sns:ConfirmSubscription",
94+
// "sns:Unsubscribe",
95+
"sns:ListTopics",
96+
"sqs:ListQueues",
97+
"dynamodb:ListTables",
98+
"s3:ListAllMyBuckets",
9399
},
94100
"Effect": "Allow",
95101
"Resource": "*",
@@ -102,7 +108,7 @@ func newLambda(ctx *pulumi.Context, name string, args *LambdaArgs, opts ...pulum
102108

103109
// TODO: Lock this SNS topics for which this function has pub definitions
104110
// FIXME: Limit to known resources
105-
_, err = iam.NewRolePolicy(ctx, name+"SNSAccess", &iam.RolePolicyArgs{
111+
_, err = iam.NewRolePolicy(ctx, name+"ListAccess", &iam.RolePolicyArgs{
106112
Role: res.Role.ID(),
107113
Policy: pulumi.String(tmpJSON),
108114
}, pulumi.Parent(res))

pkg/provider/pulumi/aws/policy.go

Lines changed: 73 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,27 @@
1+
// Copyright Nitric Pty Ltd.
2+
//
3+
// SPDX-License-Identifier: Apache-2.0
4+
//
5+
// Licensed under the Apache License, Version 2.0 (the "License");
6+
// you may not use this file except in compliance with the License.
7+
// You may obtain a copy of the License at:
8+
//
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// Unless required by applicable law or agreed to in writing, software
12+
// distributed under the License is distributed on an "AS IS" BASIS,
13+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
// See the License for the specific language governing permissions and
15+
// limitations under the License.
16+
117
package aws
218

319
import (
420
"encoding/json"
521
"fmt"
622

723
v1 "github.com/nitrictech/nitric/pkg/api/nitric/v1"
24+
"github.com/pulumi/pulumi-aws/sdk/v4/go/aws/dynamodb"
825
iam "github.com/pulumi/pulumi-aws/sdk/v4/go/aws/iam"
926
"github.com/pulumi/pulumi-aws/sdk/v4/go/aws/s3"
1027
"github.com/pulumi/pulumi-aws/sdk/v4/go/aws/sns"
@@ -20,9 +37,10 @@ type Policy struct {
2037
}
2138

2239
type StackResources struct {
23-
Topics map[string]*sns.Topic
24-
Queues map[string]*sqs.Queue
25-
Buckets map[string]*s3.Bucket
40+
Topics map[string]*sns.Topic
41+
Queues map[string]*sqs.Queue
42+
Buckets map[string]*s3.Bucket
43+
Collections map[string]*dynamodb.Table
2644
}
2745

2846
type PrincipalMap = map[v1.ResourceType]map[string]*iam.Role
@@ -37,7 +55,7 @@ type PolicyArgs struct {
3755

3856
var awsActionsMap map[v1.Action][]string = map[v1.Action][]string{
3957
v1.Action_BucketFileList: {
40-
"s3:ListAllMyBuckets",
58+
"s3:ListBuckets",
4159
"s3:GetBucketTagging",
4260
},
4361
v1.Action_BucketFileGet: {
@@ -49,9 +67,10 @@ var awsActionsMap map[v1.Action][]string = map[v1.Action][]string{
4967
v1.Action_BucketFileDelete: {
5068
"s3:DeleteObject",
5169
},
52-
v1.Action_TopicList: {
53-
"sns:ListTopics",
54-
},
70+
// XXX: Cannot be applied to single resources
71+
// v1.Action_TopicList: {
72+
// "sns:ListTopics",
73+
// },
5574
v1.Action_TopicDetail: {
5675
"sns:GetTopicAttributes",
5776
},
@@ -64,9 +83,10 @@ var awsActionsMap map[v1.Action][]string = map[v1.Action][]string{
6483
v1.Action_QueueReceive: {
6584
"sqs: ReceiveMessage",
6685
},
67-
v1.Action_QueueList: {
68-
"sqs:ListQueues",
69-
},
86+
// XXX: Cannot be applied to single resources
87+
// v1.Action_QueueList: {
88+
// "sqs:ListQueues",
89+
// },
7090
v1.Action_QueueDetail: {
7191
"sqs:GetQueueAttributes",
7292
"sqs:GetQueueUrl",
@@ -78,6 +98,7 @@ var awsActionsMap map[v1.Action][]string = map[v1.Action][]string{
7898
},
7999
v1.Action_CollectionDocumentWrite: {
80100
"dynamodb:UpdateItem",
101+
"dynamodb:PutItem",
81102
},
82103
v1.Action_CollectionDocumentDelete: {
83104
"dynamodb:DeleteItem",
@@ -86,9 +107,10 @@ var awsActionsMap map[v1.Action][]string = map[v1.Action][]string{
86107
"dynamodb:Query",
87108
"dynamodb:Scan",
88109
},
89-
v1.Action_CollectionList: {
90-
"dynamodb:ListTables",
91-
},
110+
// XXX: Cannot be applied to single resources
111+
// v1.Action_CollectionList: {
112+
// "dynamodb:ListTables",
113+
// },
92114
}
93115

94116
func actionsToAwsActions(actions []v1.Action) []string {
@@ -97,7 +119,6 @@ func actionsToAwsActions(actions []v1.Action) []string {
97119
for _, a := range actions {
98120
awsActions = append(awsActions, awsActionsMap[a]...)
99121
}
100-
// TODO:
101122
return awsActions
102123
}
103124

@@ -116,6 +137,10 @@ func arnForResource(resource *v1.Resource, resources *StackResources) (pulumi.St
116137
if q, ok := resources.Queues[resource.Name]; ok {
117138
return q.Arn, nil
118139
}
140+
case v1.ResourceType_Collection:
141+
if c, ok := resources.Collections[resource.Name]; ok {
142+
return c.Arn, nil
143+
}
119144
default:
120145
return pulumi.StringOutput{}, fmt.Errorf(
121146
"invalid resource type: %s. Did you mean to define it as a principal?", resource.Type)
@@ -145,7 +170,7 @@ func newPolicy(ctx *pulumi.Context, name string, args *PolicyArgs, opts ...pulum
145170
actions := actionsToAwsActions(args.Policy.Actions)
146171

147172
// Get Targets
148-
targetArns := make([]pulumi.StringOutput, 0, len(args.Policy.Resources))
173+
targetArns := make([]interface{}, 0, len(args.Policy.Resources))
149174
for _, princ := range args.Policy.Resources {
150175
if arn, err := arnForResource(princ, args.Resources); err == nil {
151176
targetArns = append(targetArns, arn)
@@ -167,15 +192,38 @@ func newPolicy(ctx *pulumi.Context, name string, args *PolicyArgs, opts ...pulum
167192
}
168193
}
169194

170-
policyJson, err := json.Marshal(map[string]interface{}{
171-
"Version": "2012-10-17",
172-
"Statement": []map[string]interface{}{
173-
{
174-
"Action": actions,
175-
"Effect": "Allow",
176-
"Resource": targetArns,
195+
serialPolicy, err := json.Marshal(args.Policy)
196+
if err != nil {
197+
return nil, err
198+
}
199+
200+
policyJson := pulumi.All(targetArns...).ApplyT(func(args []interface{}) (string, error) {
201+
arns := make([]string, 0, len(args))
202+
for _, iArn := range args {
203+
arn, ok := iArn.(string)
204+
if !ok {
205+
return "", fmt.Errorf("input not a string: %T %v", arn, arn)
206+
}
207+
208+
arns = append(arns, arn)
209+
}
210+
211+
jsonb, err := json.Marshal(map[string]interface{}{
212+
"Version": "2012-10-17",
213+
"Statement": []map[string]interface{}{
214+
{
215+
"Action": actions,
216+
"Effect": "Allow",
217+
"Resource": arns,
218+
},
177219
},
178-
},
220+
})
221+
222+
if err != nil {
223+
return "", err
224+
}
225+
226+
return string(jsonb), nil
179227
})
180228

181229
if err != nil {
@@ -186,10 +234,10 @@ func newPolicy(ctx *pulumi.Context, name string, args *PolicyArgs, opts ...pulum
186234
for k, r := range principalRoles {
187235
// Role policies require a unique name
188236
// Use a hash of the policy document to help create a unique name
189-
policyName := fmt.Sprintf("%s-%s", k, md5Hash(policyJson))
237+
policyName := fmt.Sprintf("%s-%s", k, md5Hash(serialPolicy))
190238
rolePol, err := iam.NewRolePolicy(ctx, policyName, &iam.RolePolicyArgs{
191239
Role: r.ID(),
192-
Policy: pulumi.String(policyJson),
240+
Policy: policyJson,
193241
}, pulumi.Parent(res))
194242

195243
if err != nil {

pkg/runtime/typescript.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ func (t *typescript) LaunchOptsForFunctionCollect(runCtx string) (LaunchOpts, er
100100
return LaunchOpts{
101101
Image: t.DevImageName(),
102102
Entrypoint: strslice.StrSlice{"ts-node"},
103-
Cmd: strslice.StrSlice{"-T " + "/app/" + t.handler},
103+
Cmd: strslice.StrSlice{"-T", "/app/" + t.handler},
104104
TargetWD: "/app",
105105
Mounts: []mount.Mount{
106106
{

0 commit comments

Comments
 (0)