3

This May be a stupid question, But is it safe to access AWS Secrets from my React front end app (Hosted on AWS Amplify) In this manner ?

These Secrets are obviously not intended to be public so I dont want to use Amplify Env Variables option.

If this is not the appropriate way of loading API Secrets and keys to a Front End Application, then what is ?

var AWS = require('aws-sdk'),
    region = "us-east-2",
    secretName = "MNTSWP",
    secret,
    decodedBinarySecret;

// Create a Secrets Manager client
var client = new AWS.SecretsManager({
    region: region
});



client.getSecretValue({SecretId: secretName}, function(err, data) {
    if (err) {
        if (err.code === 'DecryptionFailureException')

            throw err;
        else if (err.code === 'InternalServiceErrorException')

            throw err;
        else if (err.code === 'InvalidParameterException')

            throw err;
        else if (err.code === 'InvalidRequestException')

            throw err;
        else if (err.code === 'ResourceNotFoundException')

            throw err;
    }
    else {

        if ('SecretString' in data) {
            secret = data.SecretString;
        } else {
            let buff = new Buffer(data.SecretBinary, 'base64');
            decodedBinarySecret = buff.toString('ascii');
        }
    }
    
    // Your code goes here. 
});
0xD1x0n
  • 686
  • 4
  • 12
  • 31

3 Answers3

3

In order for this to even work, you'd have to have some credentials on the client that had permission to access the secret. If they are truly secret then you should not do this. Anything that you request via your app is no longer secret. If you are trying to provide secure access to backend resources you should use something like Cognito and pass along a JWT.

Jason Wadsworth
  • 8,059
  • 19
  • 32
2

Because your front end runs in a web browser, because the code can easily be examined by moderately technical users, you cannot keep credentials (such as your AWS credentials) there safely. If you do that, not only are your secrets exposed, but your AWS credentials are exposed, and an attacker can do a lot of damage with those (and there are tools to scan for AWS keys).

Honestly there aren't really solid ways to protect credentials in a front-end application, so you can:

  • Use a back-end API which holds the credential securely
    • But are you just pushing the problem around? Now do you need to verify that the user should have access to the back-end API?
  • Have the user supply credentials
    • This is the most common approach -- the user provides username and password and you use that to control access
    • This may still require a back-end API or something that can parse the credentials (e.g. AWS API Gateway + Authorizer)
  • Work out complicated rules to protect back-end resources even when some level of key is exposed (e.g. see Firebase Security Rules).
Geoffrey Wiseman
  • 5,459
  • 3
  • 34
  • 52
  • 1
    I'm not sure about this accepted answer. It seems possibly incorrect - not sure. "But are you just pushing the problem around? Now do you need to verify that the user should have access to the back-end API?" That seems to be the whole reason the AWS SDK has it's secretsmanager set-up and why one would use Amplify/Lambda/SecretsManager in AWS. Are you saying that doesn't in fact work or? – Rogelio Aug 12 '22 at 03:34
  • I'm saying that if you want to protect a secret, then bringing that secret into an environment you can't fully protect is maybe something you want to avoid. Keeping a secret in Secrets Manager is ok. Loading that secret out of secret manager into front-end JavaScript code is likely to leak that secret if someone wants it badly enough. Using a Lambda to access a secret is more likely to be ok -- that's what AWS recommends: https://docs.amplify.aws/cli/function/secrets/ – Geoffrey Wiseman Aug 13 '22 at 01:28
1

That's you may need to save your credentials information into Secret Manager first, then fetch as follow:

var AWS = require('aws-sdk'),
  region = "ap-southeast-1",
  secretName = `my-secret`, rds_username, rds_password;

var awsSecretClient = new AWS.SecretsManager({
  region: region
});

let result = await awsSecretClient.getSecretValue({ SecretId: secretName }).promise();
rds_username = Buffer.from(JSON.parse(result.SecretString).rds_username, 'base64').toString();
rds_password = Buffer.from(JSON.parse(result.SecretString).rds_password, 'base64').toString();
PPShein
  • 13,309
  • 42
  • 142
  • 227