Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement support for AWS SecretsManager #4

Open
wants to merge 4 commits into
base: main
Choose a base branch
from

Conversation

natepage
Copy link

@natepage natepage commented Aug 8, 2023

Hi there 馃憢

secrets-loader is great, easy to setup, and works beautifuly with AWS SSM.

However, most of our projects work with both SSM and SecretsManager,
This PR allows people to use natively use secrets from SecretsManager with Bref.

@mnapoli
Copy link
Member

mnapoli commented Aug 8, 2023

It seems the tests are failing because of Undefined array key "AWS_DEFAULT_REGION": you might want to force an AWS_REGION in the test class?

@natepage
Copy link
Author

natepage commented Aug 8, 2023

@mnapoli this was a legit error, the SecretsManagerClient shouldn't not be called in the failing test. The issue was triggered by of a contengency between tests because we're using putenv() to set the env variables and it carries between test.
I've explicitly removed the env variable from previous test and it's all green now

@natepage
Copy link
Author

natepage commented Aug 8, 2023

@mnapoli I've pushed a last fix for symfony/polyfill-uuid, it's required by async-aws/secrets-manager. However, checking their releases, 1.13.0 was broken and it was fixed 2 days later in 1.13.1

You can see this in their changelog, it fixes the issues with constants: https://github.com/symfony/polyfill/blob/1.x/CHANGELOG.md#1131

@jaulz
Copy link

jaulz commented Sep 25, 2023

@natepage nice work 馃槉 Do you already use it? I assume it also needs some adjustments here:
https://github.com/brefphp/bref/blob/master/src/LazySecretsLoader.php#L36 ?

if ($e->getCode() === 400) {
// Extra descriptive error message for the most common error
throw new RuntimeException(
"Bref was not able to resolve secrets contained in environment variables from SecretsManager because of a permissions issue with the SecretsManager API. Did you add IAM permissions in serverless.yml to allow Lambda to access SecretsManager? (docs: https://bref.sh/docs/environment/variables.html#at-deployment-time).\nFull exception message: {$e->getMessage()}",
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be cool to try to get all the secret values first and afterwards throw the error (including indicating which secrets have failed).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In case of a permission issue it's more likely that permissions are not good for all secrets. If not, that's not a common case, I'm fine keeping it simple honestly (easier to maintain).

@mnapoli
Copy link
Member

mnapoli commented Sep 29, 2023

I don't use SecretsManager and I have one hesitation before merging this: isn't it more common to store multiple variables in 1 SecretManager entry?

That's a pattern I've seen multiple times, and I think it's caused by the fact that SecretManager deals well with JSON values (so multiple values in 1 secret) and that secrets are expensive (by the unit). It also means 1 HTTP call (faster and cheaper) to retrieve all values.

For example, that's how secrets are stored for AWS services: https://docs.aws.amazon.com/secretsmanager/latest/userguide/reference_secret_json_structure.html

@jaulz
Copy link

jaulz commented Sep 29, 2023

I don't use SecretsManager and I have one hesitation before merging this: isn't it more common to store multiple variables in 1 SecretManager entry?

Are you referring to this PR or #7? This PR indeed assumes that all secrets are in JSON format but actually you can also just store simple strings and it would fail then.

This is how this PR works:

Secrets:

DB_CONNECTION: { "host": "example.org", "username": "test", "password": "test" }

serverless.yml:

provider:
  environment:
    DB_CONNECTION: bref-secretsmanager:DB_CONNECTION

Expands to these environment variables:

DB_CONNECTION={ "host": "example.org", "username": "test", "password": "test" }
host=example.org
username=test
password=test

However, I think it should simply expand to the actual value (see #7) and the rest is up to the application to parse it properly:

DB_CONNECTION: { "host": "example.org", "username": "test", "password": "test" }

It's unopinionated and would work exactly the same like the bref-ssm: prefix.

@natepage
Copy link
Author

natepage commented Oct 2, 2023

Hey there, sorry I missed the party 馃槃

@mnapoli agree with you here, all projects I worked on using AWS SecretsManager are storing multiple variables in a single secret.
However, @jaulz got a point, the current implementation wouldn't support secrets that aren't valid JSON values.

What about introducing some kind of processor, similar to what Symfony does with their env variables?
We could support both:

  • bref-secretsmanager:MY_SECRET => Simply set env var with whatever value from AWS
  • bref-secretsmanager:json:MY_SECRET => JSON decode value from AWS and set individual env vars

I'm happy to push changes to support this if sounds good to you!

@natepage
Copy link
Author

natepage commented Oct 2, 2023

The changes to add a json processor were not too hard so I went ahead and did it so you can have a look a decide, I added a test to illustrate how it would work

@natepage
Copy link
Author

Hey there, Happy New Year!

A gentle follow up on this one as we would to be able to use this in our projects 馃槃

@@ -19,9 +19,11 @@
"async-aws/ssm": "^1.3"
},
"require-dev": {
"async-aws/secrets-manager": "^1.0",

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it OK to put this in the require-dev instead of in the require section?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@f-lombardo my thinking was people don't need this dependency unless they are working with secrets manager, and because ssm is the default implementation of this library it's most likely to be the only use in a majority of cases. But I do not have strong opinions about it 馃槃

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMHO since async-aws/ssm is in the require section, the same should hold for async-aws/secrets-manager

@f-lombardo
Copy link

Hey there, Happy New Year!

A gentle follow up on this one as we would to be able to use this in our projects 馃槃

Hello @natepage, since I also had to use some new features in a few projects, I created a small fork of this one: https://github.com/f-lombardo/secrets-loader

If you want, you could submit a PR to my repo too. I'll take care of mantaining my project aligned with the original one

@f-lombardo
Copy link

Hey there, sorry I missed the party 馃槃

@mnapoli agree with you here, all projects I worked on using AWS SecretsManager are storing multiple variables in a single secret. However, @jaulz got a point, the current implementation wouldn't support secrets that aren't valid JSON values.

What about introducing some kind of processor, similar to what Symfony does with their env variables? We could support both:

* `bref-secretsmanager:MY_SECRET` => Simply set env var with whatever value from AWS

* `bref-secretsmanager:json:MY_SECRET` => JSON decode value from AWS and set individual env vars

I'm happy to push changes to support this if sounds good to you!

I've implemented something similar here:
https://github.com/f-lombardo/secrets-loader/blob/master/README.md

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants