Question on security with Cognito UserPools: If we...
# sst
l
Question on security with Cognito UserPools: If we're doing a monorepo, and we anticipate sharing said UserPool across multiple microservices, then it's likely a common pattern to use cross-stack references?
f
Hey @Luke Wyman, r u asking if you export the cognito user pool values in 1 stack and importing it into another stack introduces security issues?
l
Hi @Frank - no, not the security issues. The shared resource I'm working on is coincidentally about security. I'm asking about cross-stack references in general. Looking at the sst constructs, what is the approach/syntax for my microservice stacks, say
SingersStack.ts
,
PerformanceHistoryStack.ts
, etc, to reference
CognitoStack.ts
and apply the Cognito Pool to the APIs in those microservices.
f
Ah I see. Just to clarify, are you just using the Cognito User Pool as a JWT authorizer? Or are you using the
sst.Auth
construct?
l
That's something I haven't decided yet. I'm currently doing all the Cognito/JWT/Auth0 examples in the documentation and researching all this in general before I pick a strategy for my app. What I know in advance, is that I'll have a Cognito stack of some sort or other, and that I'll want to share it with my microservices. I can repost here when I have a crisper picture of what I want to do.
I'm probably going to want to pick something of professional/production quality.
Hi @Frank - I think I understand the question better now. Yes, I do want to use the
sst.Auth
construct. So, if I have an auth declared in say a
FacebookStack.ts
, and I'd like to reference the auth in the api of a
[Microservice Name]Stack.ts
, what is the syntax for that?
f
Yeah, there are two common ways to implement API auth: using the
Auth
construct or using the JWT token issued by Auth0,
Cognito User Pool
or any third party auth provider.
Generally speaking, the recommended way is to use the
Auth
construct. And to authorize your API, you don’t need to pass the
Auth
construct around, you just need to set the
authorizationType
to
IAM
in your
sst.Api
construct.
You can find a couple of examples here under the
Authorization
section https://serverless-stack.com/examples/index.html
l
Okay. So, say that the following are a couple lines from my example code:
Copy code
const auth = new sst.Auth(this, 'Auth', {
      facebook: { appId: 'xxxxxxxxxxx'},
    });

    auth.attachPermissionsForAuthUsers([api]);
but that
auth
and
api
live in different
____Stack.ts
files. What is the syntax/technique for of connecting the two in the
auth.attachPermissions...
line? Can I just export the
auth
in it's
.ts
file and import it in my
MicroserviceStack.ts
file?
f
ie. in
lib/AuthStack.ts
Copy code
const auth = new sst.Auth(...);
this.auth = auth;
in
lib/index.ts
Copy code
const authStack = new AuthStack(app, "auth");
new ApiStack(app, "api", { auth: apiStack.auth });
in
lib/ApiStack.ts
Copy code
const api = new sst.Api(...);
props.auth.attachPermissionsForAuthUsers([api]);
l
Awesome! Thanks, Frank 🙂
And I imagine this technique can be used to share other resources, say, an SQS queue, for example?
f
Yup!
e
So this seems to work, but doesn’t it then require that AuthStack must be deployed at the same time as ApiStack? Would it make more sense to share the values as SSM parameters and use fromXXX to get the resource?
f
Hey @Erik Mikkelson, yeah you could store the Api id as an SSM parameters, and then reference the SSM value when creating the Identity Pool’s authenticated IAM role.
But why not creating the Auth and Api at the same time? Are you importing an existing User Pool/Identity Pool?
e
@Frank Even though I’ve used the CDK for a bit there are a few places I am missing some understandings so forgive crazy ideas. I am trying to think a bit about an individual and shared developer experience. An individual developer is going to want some local development with services under tight control (I think most easily accomplished for initial lambda development by unit tests with mocks for aws services and generated test data. We’re using rushjs and pnpm so that made VSCode debugging interesting until I created a helper script to launch tests under the context of the target package). Once they have that working, it makes sense for them to deploy developer environments if they need it. We’re already planning on separating out the stacks into layers based on the amount of change (the three layers) Not all developers are going to deploy their own user pools and aurora DBs (which are more expensive in terms of deployment time and general cost), so in cases where they could reuse a shared user pool, database, and perhaps even some of the s3 buckets for assets I’d like to at least investigate that. In order to do that, you can’t have such a hard link between the stacks. Storing the resource arns as outputs for a stage in the parameter store where they can be looked up on deploy makes more sense.
What approaches have you seen people use for larger teams?
f
Gotcha. As for $ cost, if each developer has their own AWS account, hence free tier, then you can have ie. an Aurora DB cluster of size 1 running a small instance for free.
The n-layer approach is pretty common too. For example, 1 SST app for “dbs/user pools/buckets”, and 1 SST app for “api/topics/queues”.
And the former app has 1
dev
stage, and the latter app has
dev-erik
,
dev-frank
, stages, and all
dev-*
stages connect to the same DB in the
dev
stage
e
@Frank You mean their own AWS account as in actually different accounts (different credit cards, etc) or AWS Organizations?
f
Sub accounts within the same AWS Organization. Each has their own free tier.
e
I did not know that, thank you for the information!