My role policy is unable to create new roles. Is t...
# help
z
My role policy is unable to create new roles. Is there a way to set default function props / stack synthesizer for the debug stack, so I can provide it the necessary roles and doesn’t try to create them?
f
Hi @Zack McKenna, currently there isn’t a way.. but let me pull in @thdxr and @Jay to see how best we can do this.
Currently , the only customization for the debug stack that’s exposed to user is AFTER the debug stack is created, ie.
Copy code
// index.js

export function debugStack(app, stack, props) {
  ... stack is already created ...
}
z
Oh man, I appreciate it! It’s a real pain. I’m working with our cloud team to maybe allow us to within a permission boundary, but until then …
f
Yeah, setting permission boundary for the debug stack is straight forward, here’s an example https://docs.serverless-stack.com/constructs/RDS#migrations
z
Yeah, I’m relatively new to cdk, but it seems like you can’t set default props or change the default synthesizer after they’ve been created
f
hmm… wait.. there might be a way…
So all resources in a stack is like a tree, the root node being the
Stack
object.
I ahven’t tried this, but I wonder if u can traverse through the `Stack`’s children and remove the roles that were created and replace them w/ your own roles
z
that’s definitely worth a shot! I’ll look into it
f
It’d look something like:
Copy code
// index.js

export function debugStack(app, stack, props) {
  stack.node.children.forEach((resource) => {
    // check resource instanceof iam.Role
  });
}
We actually do this pattern in quite a few places in our code. Here we recursively loop through each child and update them (ie. apply removal policy) https://github.com/serverless-stack/serverless-stack/blob/master/packages/resources/src/App.ts#L316
The part I haven’t tried is removing a child from the tree. But yeah worth a shot.
z
Oh woah, that’s rad
yeah, I’ll give it a shot and let you know how it goes!
thanks so much
f
Hey @Zack McKenna just checking in and see if you had any luck w/ this.
z
Hey @Frank, thanks for checking in! I got sidelined by some other tasks so I haven’t been able to dedicate more time to it yet, but I should be able to spend some good time on it tomorrow.
f
I just talked to the team and we spec’ed out a way to make the DebugStack more customizable.
I will try to put something together today.
Just to make sure it cover ur use case. The debug stack creates a couple of IAM roles: • 1 for each of WebSocket API routes: $connect, $disconnect, and $default • 1 for auto removing objects in the s3 bucket on delete debug stack • 1 for setting Lambda log retention Do you want to pass in a role for each of these? Or are you looking for a way to name these roles that follow a certain rule?
z
Oh, that’s awesome! Yeah, exactly. It’s real silly, but because of how our roles are created/set up (via a third party), any role that needs to be created needs to be done manually beforehand. As long as I can provide a previously created role/arn, that would be perfect. Since Tuesday, I’m still waiting to hear back from our cloud team in regards to letting us use create role within a permission boundary, buuut I have no idea when I might get an answer.
Actually, I realized there are a few more roles missing that need to be passed for my use case: the deployArn and cloudFunctionExecutionArn set in the synthesizer, unless there is a way to remove/replace/edit the synthesizer after the stack has been created instead. I’m looking into it.
f
Yeah, you will be able to edit the synthesizer.
Thinking ahead, do you also need a way to override all the other IAM roles in your app?
ie. if you were to use
sst.Api
, you’d need to override the roles for all the routes?
Hey @Zack McKenna, I pushed out a change in v0.65.3 that lets you edit synthesizer for the DebugStack like this;
Copy code
export function debugApp(app) {
  new sst.DebugStack(app, "debug-stack", {
    synthesizer: new cdk.DefaultStackSynthesizer({
      ...
    }),
  });
}
This will let you pass in the
deployRoleArn
and
cloudFormationExecutionRoleArn
I can make another release to support passing in the iam roles like this:
Copy code
export function debugApp(app) {
  new sst.DebugStack(app, "debug-stack", {
    synthesizer: ...,
    websocketHandlerRoleArn: "arn:...",
    lambdaLogRetentionRoleArn: "arn:...",
    ...,
  });
}
But before I proceed, I’d wanted to hear your thoughts on the above:
Thinking ahead, do you also need a way to override all the other IAM roles in your app?
ie. if you were to use 
sst.Api
, you’d need to override the roles for all the routes?
Let me know.
z
Yeah, I believe that’s the case. Though, by setting a the role within function props, it seems to use that instead of attempting to create new roles for the api routes. So I guess the ability to override that is currently there?
Fortunately, I’ve been able to make some headway with our cloud team in regards to setting up the roles which can actually use create role. Though, this requires some certifications on our team’s end and will take some time, so being able to use the debug stack while I work on a POC is invaluable.
f
Sounds good. I will put something together for the debug stack for now.
Hey @Zack McKenna, I just released v0.66.0. You can now pass in a role to the DebugStack like this https://docs.serverless-stack.com/constructs/DebugStack#configuring-the-debug-stack
Give it a quick try. And let me know whatelse u need to get it to work.
z
awesome! thanks so much. I’ll give it a go
Copy code
zmcken282-serverless-my-debug-stack | CREATE_FAILED | AWS::IAM::Role | CustomS3AutoDeleteObjectsCustomResourceProviderRole3B1BD092 | API: iam:CreateRole User: arn:aws:sts::311732959032:assumed-role/IhatLambdaRole/AWSCloudFormation is not authorized to perform: iam:CreateRole on resource: arn:aws:iam::311732959032:role/zmcken282-serverless-my-d-CustomS3AutoDeleteObject-1EIO9SKO5VTEY
hmm, looks like it’s still trying to create a role for the S3 autodelete.
f
Can you try passing in an existing bucket, like this:
Copy code
export function debugApp(app) {
  new DebugStack(app, "debug-stack", {
    payloadBucketArn: "arn:aws:s3:::my-bucket",
    websocketHandlerRoleArn: "...",
  });
}
This way, the debug stack won’t try to create a bucket.
Let me know if that works for you.
z
I had to put this down for a bit but I’ve finally been able to jump back into it. Thanks again for all your help. I was finally able to get the debug stack to work with those changes, and I was able to set things up with our governance team so roles could be generated dynamically, in the end applying an aspect to the debugStack to set a specific path and attach a required policy to each role created in order to satisfy their policy requirements. Similar what you suggested a little while ago before I had the right accounts to do so:
Copy code
class CustomRoleAspect {
  constructor(permissionBoundaryArn, path) {
    this.permissionsBoundaryArn = permissionBoundaryArn
    this.path = path
  }

  visit(node) {
    if (CfnResource.isCfnResource(node) && node.cfnResourceType === 'AWS::IAM::Role') {
      node.addPropertyOverride('PermissionsBoundary', this.permissionsBoundaryArn)
      node.addPropertyOverride('Path', this.path)
    }
  }
}
Now although the debug stack is deployed, I am getting a 403 error in the stub lambda:
Copy code
type: 'error',
  message: 'Unexpected server response: 403',
  error: Error: Unexpected server response: 403
      at ClientRequest.<anonymous> (/var/task/node_modules/ws/lib/websocket.js:604:7)
      at ClientRequest.emit (events.js:400:28)
      at ClientRequest.emit (domain.js:475:12)
      at HTTPParser.parserOnIncomingClient [as onIncoming] (_http_client.js:647:27)
      at HTTPParser.parserOnHeadersComplete (_http_common.js:127:17)
      at TLSSocket.socketOnData (_http_client.js:515:22)
      at TLSSocket.emit (events.js:400:28)
      at TLSSocket.emit (domain.js:475:12)
      at addChunk (internal/streams/readable.js:293:12)
      at readableAddChunk (internal/streams/readable.js:267:9)
and a 503 from within the api gateway.
Copy code
{
  "requestTime": "15/Mar/2022:14:54:58 +0000",
  "requestId": "PB9OYjYdIAMESOg=",
  "httpMethod": "GET",
  "path": "/",
  "routeKey": "ANY /",
  "status": 503,
  "responseLatency": 30005,
  "integrationRequestId": "-",
  "integrationStatus": "-",
  "integrationLatency": "30000",
  "integrationServiceStatus": "200",
  "ip": "198.178.12.68",
  "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.51 Safari/537.36",
  "cognitoIdentityId": "-"
}
I assume this might have something to do with permissions/policies, unless there might be something else I should look into before diving into it?
Although I believe it is reaching my client, since if I don’t have
sst start
running, I see
Client not connected. Make sure "sst start" is running.
Ah due to problems with VPC/Public WebSockets. Removing the vpc for IS_LOCAL seemed to do the trick.
f
@Zack McKenna oh wow glad u got it to work!
problems with VPC/Public WebSockets
Was the issue that Lambda in VPC wasn’t able to talk to the public WS?
z
Yup!
But now it’s working great, by just making sure the debug lambdas aren’t within the VPC. Thanks so so much for all the help, I can’t tell you how psyched I am to share it with the team once I translate our app to SST, the live lambda development is truly INCREDIBLE. I’ll try to compile what I can in a blog post about it since I’m sure other people might run into similar issues int he future working within larger corps.
j
That would be super helpful Zack! And glad you are liking it!