I’m working on a stack that involves creating an O...
# help
a
I’m working on a stack that involves creating an OpenIdConnectProvider (Okta in our case) in AWS IAM to use with a Cognito Identity Pool for granting access to some AWS resources using tokens from Okta. It seems this resource cannot be duplicated within a single AWS account. The identity pool can be unique to each stage even if using the same OIDC Provider, but I’m wondering if there is an established pattern for creating a one-per-account resource like this, regardless of the number of stages. We have a shared sandbox account for developers so many people might deploy this stack but need to share that OIDC provider resource. I don’t really like the workflow constraints that come with having a dedicated “shared” stage for this one shared resource. I’m curious if there is a way to essentially only try to create the resource if it doesn’t already exist?
s
Hi Austin, I've been playing with this concept as well
Sometimes there are shared resources that we may not want to duplicate per stage (e.g. VPCs, security groups, RDS databases, etc)
I have a team of dozens of developers, and I don't want to spawn a new User Pool for each development environment. A shared User Pool is fine for my development use case. In this scenario, I've created a
SharedAuthStack
construct that conditionally creates the UserPool if the stage is set to dev/stage/prod (or whatever long-lived environments you define). If the stage is anything else (an ephemeral development environment, for example), I use the existing
dev
User Pool.
It looks something like this
Copy code
import * as cognito from 'aws-cdk-lib/aws-cognito';

const LONG_LIVED_STAGES = ['dev', 'stage', 'prod'];
export default class SharedAuthStack extends sst.Stack {

constructor(scope: <http://sst.App|sst.App>, id: string, props?: SharedAuthStackProps) {
    super(scope, id, props);

    // if you are deploying to an ephemeral stage
    if (!LONG_LIVED_STAGES.includes(scope.stage)) {

      // import the existing development User Pool ID
      const userPoolId = // lookup value from SSM

      // import the existing development User Pool ID
      // get the development user pool
      this.userPool = cognito.UserPool.fromUserPoolId(
        this,
        'dev-user-pool',
        userPoolId
      );

      return
     } 

    // Create new User Pool
    this.userPool = new cognito.UserPool(...)

    // Create SSM parameter for the newly created User Pool
    new ssm.StringParameter(...)
}
Not sure if this is the best way, but it's the approach I've been experimenting with recently. Would love to hear how others are solving this problem
j
Does it mean that someone still have to deploy
dev
before developers can start using it? Or do you let it create "lazily" by any (developer) stage that needs it?
s
@Jan Plaček That's correct, I'd have to deploy the SharedAuthStack to
dev
first
I think the syntax is something like,
sst deploy SharedAuthStack --stage dev
It's an extra manual step, so I'm not sure I love it. But it seems to work 🤷
j
I think it's fine. I would probably try to create it whenever possible, I am just not sure if it would be always possible due to a lack of permissions or something.
a
@Seth Geoghegan @Jan Plaček thanks for the feedback/suggestions. This gives me some things to try!
s
@Jan Plaček How do you mean "create it whenever possible"?
Do you mean avoid shared resources?
j
No no, I mean from any stage that needs it, but still shared. Obviously you must manually provide the resource name (rather then letting SST to prefix it with current stage). ... Not sure sure if it's actually easily doable, when speaking of it....
f
You could use a Custom Resource to implement a logic of first stage creates (owns) the resource, and the stages that come after reuse it.
With this approach, u don’t have Seth’s problem of always having to deploy
dev
before deploying other stages. But you will run into the opposite problem of need to track which stage created (owns) the resource, and make sure that stage does not get removed.
I find @Seth Geoghegan’s solution to be both easier to implement and easier to manage 😁