safeguards-plugin icon indicating copy to clipboard operation
safeguards-plugin copied to clipboard

"serverless deploy" continues to run while async policies are processing

Open sc0ttdav3y opened this issue 3 years ago • 1 comments

Hi,

I've written an asynchronous policy that returns a promise and it works, but I'm wondering whether I've implemented it correctly because serverless deploy seems to continue running while the plugin is evaluating its condition.

Is there something I've missed in documentation about writing async policies, or does the safeguards plugin itself not await them?

The good news is the policy works. But the bad news is serverless continues to run while it's evaluating.

Here's an example output.

   Summary --------------------------------------------------

   passed  - No secrets in lambda ENV VARs
   passed  - no secret ENV vars
  running - No deploy to blocked accountsServerless: Uploading CloudFormation file to S3...
Serverless: Uploading artifacts...
Serverless: Uploading service hello-fullstack.zip file to S3 (23.68 MB)...
   passed  - No deploy to blocked accounts

Serverless: Safeguards Summary: 3 passed, 0 warnings, 0 errors, 0 skipped

You can see the two lines from my plugin:

running - No deploy to blocked accounts
passed  - No deploy to blocked accounts

But before it passes, you can also see serverless begin to upload my stack.

My plugin looks like this:

const AWS = require('aws-sdk');

/**
 * Denies deploying this project to the blocked AWS accounts.
 *
 * @param policy
 * @param service
 * @param options
 */
module.exports = async function noDeployToBlockedAccountPolicy(policy, service, options) {
    // @see https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/STS.html#getCallerIdentity-property
    const sts = new AWS.STS();

    if (!Array.isArray(options.accountIds)) {
        policy.fail(`The policy no-deploy-to-blocked-accounts is missing a 'config.accountIds' array.`);
    }

    try {
        const data = await sts.getCallerIdentity({}).promise();
        if (options.accountIds.includes((parseInt(data.Account)))) {
            policy.fail(
                `Your current AWS account ${data.Account} is blocked from deployment. ` +
                `Switch to another account and try again.`);
            return;
        }
        policy.approve();
    } catch (err) {
        console.error(err, err.stack);
        policy.fail(`An error occurred`);
    }
};

And it's configured as follows:

custom:
  safeguards:
    - title: No deploy to blocked accounts
      safeguard: no-deploy-to-blocked-accounts
      path: ./policies
      config:
        accountIds:
          - XXXXX
          - YYYYY

Is there a way to make the safeguards plugin await my policy?

Thanks in advance... Scott

sc0ttdav3y avatar May 06 '21 03:05 sc0ttdav3y

Hello @sc0ttdav3y :wave: I believe the issue might lie here: https://github.com/serverless/safeguards-plugin/blob/813d594ed12302923f985554ff828e4763e4f55c/index.js#L94 where the promise is orphaned and never awaited.

We'd be happy to accept a fix for this from the community (and verifying if that's the actual problem). :raised_hands:

pgrzesik avatar May 10 '21 11:05 pgrzesik