-
Notifications
You must be signed in to change notification settings - Fork 481
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’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Use AWS secret for chef config overrides #36366
Conversation
fbd5196
to
1999a17
Compare
Realized that we'll need to update these attributes before both calls to Line 36 in c1e8b15
Line 121 in c1e8b15
This could make things quite a bit messier and harder to maintain- I might spend a bit more time rethinking the approach to see if there are any simpler alternatives. |
Add a Secrets Manager secret to CloudFormation stack, containing stack-wide Chef cookbook attributes. Pass attributes as argument to chef-client in bootstrap and CI.
125c1b2
to
304ae3d
Compare
Properties: | ||
Description: !Sub "Custom Chef attributes for ${AWS::StackName} CloudFormation stack" | ||
Name: !Sub "CfnStack/${AWS::StackName}/chef" | ||
SecretString: '{}' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Might be useful to mention that we manage the values stored in this Secret manually (outside of this CloudFormation template).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done in 4155489.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just checking that I understand the migration plan - with these changes, chef attributes will be set both from Secrets Manager (via --json-attributes
) and from the Hosted Chef server. In the middle step, where they'll be set in both places, the values from Secrets will override the ones from Hosted Chef (though it won't really matter because the values should be identical in both places.) Is this right?
sudo -u ubuntu bash -c "aws s3 cp <%=bootstrap_script_path%> - | sudo bash -s -- $OPTIONS" | ||
[ $? -eq 0 ] && STATUS=SUCCESS || STATUS=<%=daemon ? 'SUCCESS' : 'FAILURE'%> | ||
|
||
# Bash script that invokes chef-client with fetched config attributes and provided run-list. | ||
CHEF_CLIENT_BIN=<%=CHEF_CLIENT_BIN%> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks fine to me, but I was curious on your thoughts on inlining this here, rather than uploading to S3 like we do for chef-bootstrap.sh
. (Why isn't chef-bootstrap.sh
just part of this script, anyway? Is it just to break up this script into smaller chunks?)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was curious on your thoughts on inlining this here, rather than uploading to S3 like we do for
chef-bootstrap.sh
.
The parameterized arguments ${Chefconfig}
(which is a reference to the CFn resource) and $RUN_LIST
(which is a reference to the run_list
option passed from the stack ERB including this script) make it more complicated to render this script to S3 at compile-time like we do chef-bootstrap.sh
, especially since this script is being invoked from the CI-build as well, not just from this bootstrap script.
Why isn't chef-bootstrap.sh just part of this script, anyway? Is it just to break up this script into smaller chunks?
chef-bootstrap.sh
was an experiment with deploying a self-contained bash script partly to break apart the bootstrap script as you guessed, but also because I thought that its purpose was narrow/isolated enough that it could be written as a standalone script, manually deployed once to a static location and touched very rarely after that.
That experiment turned out to be challenging as soon as it became a production-build dependency: deploying any meaningful change to the script required either careful backwards-compatibility with each change, and/or synchronization across all environments to prevent breaking the production workflow. So to avoid these issues (without setting up a whole more elaborate versioning, packaging and deployment system for such a tiny thing), I made a change to deploy it to a separate path per stack. So now it's basically tied to the stack anyway, contrary to the original design. It could be in-lined at this point to reduce the overall complexity (with some additional work).
lib/cdo/cloud_formation/cdo_app.rb
Outdated
@@ -24,6 +24,7 @@ class CdoApp < StackTemplate | |||
end | |||
|
|||
# Hard-coded constants and default values. | |||
CHEF_CLIENT_BIN = '/usr/local/bin/chef-client' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we name both the variable and the file itself something that indicates it's not just another copy of chef-client
? It's clear from this PR, but confusing if you see it in isolation. Maybe something like chef-client-with-secrets
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about chef-cdo-app
, to make it clear it's invoking chef
to provision cdo-app
(see 60b476c).
Update this secret manually after the stack is created to customize Chef configuration. The value should never be changed in the stack itself, since it would clobber all other changes.
(CI unit-test failure seems unrelated..) |
Yes, this is correct! |
Fixes constant not found error. Followup to #36366.
Partial revert of #36366. The script needs to be created on existing environments by rebooting existing instances before the path can be safely updated.
Use AWS secret for chef config overrides
Overview
This PR adds a Secrets Manager secret to the Code.org application CloudFormation stack. The secret is a JSON string containing stack-wide Chef cookbook attributes. The value contained in this secret is passed as an argument to
chef-client
whenever our system invokes Chef, whether as part of its bootstrapping process or through a CI build.Background
This AWS secret providing chef-config attributes will help transition existing cookbooks comprising our application's provisioning process from hosted to local-mode Chef. Specifically, the Chef Environment Attributes and Role Attributes currently stored in Hosted Chef Server will be manually merged and stored in this secret, then eventually deleted from the Hosted Chef resources.
This is the last part of our Chef provisioning depending on state stored in the Hosted Chef Server repo.
Implementation details
SecretsManager::Secret
resource's logical id is ChefConfig, and the secret name isCfnStack/[StackName]/chef
.chef-client
whenever our system runs Chef, a new shell script is written toCdo::CloudFormation::CdoApp::CHEF_CLIENT_BIN
(a constant equal to'/usr/local/bin/chef-client'
) which fetches the secret (viaaws secretsmanager get-secret-value
) and passes it tochef-client
(via the--json-attributes
option). Existing calls to/opt/chef/bin/chef-client
in our CI build scripts have been updated to call this helper script instead.first-boot.json
file it creates. In order to ensure these first-boot attributes are applied in addition to the secret attributes, a separate call tochef-client
with an empty runlist is now done first to persist the first-boot attributes to the newly-created Chef node.Test Story
Migration Plan
baseline
role attributes for each stack/environment)