-
Notifications
You must be signed in to change notification settings - Fork 1.2k
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
Add SSL support to local start-api and start-lambda #5902
Conversation
Thanks a lot for working on this change! Since this involves certificates, it is better to confirm changes with security team. We will be booking some time with them and come back to you if they have any suggestions. |
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.
Thanks again for your contribution and you patience. We've got approval to move forward for this change, I left some comments in the PR.
click.option("--ssl-cert-file", default=None, help="Path to SSL certificate file (default: None)"), | ||
click.option("--ssl-key-file", default=None, help="Path to SSL key file (default: None)"), |
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.
Does defining one of these parameter will require other to be present? If so we can add a validation for that.
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.
Yes, both the certificate and and key must be specified in order for SSL to work. I'll see about adding that validation.
error_message = ( | ||
"SSL key file must be present if certificate is present" | ||
if ssl_key_file is None | ||
else "Invalid certificate and/or key file" | ||
) |
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.
Is this the case all the time? Can we just re-surface the original error caught here?
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.
If I add the “if either is present, both must be present” validation you suggested above, we can probably just remove this block entirely and let the SSLError
bubble up on its own. I only added it to differentiate between a real “bad cert or key” error and a missing key.
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.
My bad, I think I've read this line wrong at first, but now it makes more sense.
If you think SSLError
text is good enough, we can bubble up the error or just its message back to the user. And once we are surfacing these errors, we need to make sure we are raising UserError
so that CLI will handle them gracefully rather than crashing with exception trace (I can check that one later once you made the changes).
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 think the SSLError
text is good enough (and I'm not sure we can cover all possible SSL Errors with our own text anyway), but I'll still catch it and wrap it in a UserError
. The click options validator will catch the other case of mutually inclusive options.
bc4ca00
to
788fcea
Compare
I've added a validation callback to the CLI options spec to make sure that I see what you mean about using Come to think of it, Flask is using |
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.
One small comment form my side, rest is looking good, thanks again for the changes!
The value can be a (cert, key) tuple, a full ssl.SSLContext object, or the string 'adhoc' (to use a one-off self-signed certificate). In order to keep this both simple and relatively safe, I went with the tuple. If a higher-level class is preferable, I could just create an ssl.SSLContext here and pass that around instead.
Regarding to this ^, let's keep tuple instead, I don't want to include 3rd part object/type into this code base in case they will change its definition in the future.
click.option("--ssl-cert-file", default=None, callback=validate_ssl_params, help="Path to SSL certificate file (default: None)"), | ||
# Mark --ssl-key-file as eager, so by the time the --ssl-cert-file validator is invoked, we know if it's missing | ||
click.option("--ssl-key-file", default=None, callback=validate_ssl_params, is_eager=True, help="Path to SSL key file (default: None)"), |
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.
Sorry that I missed this in the first round but we could use Click's file path arguments which will provide some basic path validation out of the box. https://click.palletsprojects.com/en/8.1.x/arguments/#file-path-arguments
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.
Nice catch, thanks. That does make things a lot simpler, and eliminates the need to call the custom validator on the first pass.
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've updated one output which was missing https
if these parameters are set. Other than that it looks good to me now.
One final question, do you think this will be useful for sam local start-lambda
? If not I think we can remove these parameters for that command and keep it only for sam local start-api
for now.
I don't really know. I don't have a use case for it. The only reason I added it in the first place was because of the common set of kwargs that get passed down to both service classes. I'm not opposed to removing the command line options as long as you don't mind having those unused arguments hanging out on the lambda class. |
@mndeveci Would you like me to change this so that the parameters only apply to |
I can't find request to add this for |
# Mark --ssl-key-file as eager, so by the time the --ssl-cert-file validator is invoked, | ||
# we know if it's missing |
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.
nit: Another option is to use the ClickMutex class we have to set these two options as required.
An example of this being implemented can be found here:
aws-sam-cli/samcli/commands/init/command.py
Lines 117 to 130 in 2a527fd
@click.option( | |
"--no-interactive", | |
is_flag=True, | |
default=False, | |
help="Disable interactive prompting for init parameters. (fail if any required values are missing)", | |
cls=ClickMutex, | |
required_param_lists=[ | |
["name", "location"], | |
["name", "package_type", "base_image"], | |
["name", "runtime", "dependency_manager", "app_template"], | |
# check non_interactive_validation for additional validations | |
], | |
required_params_hint=REQUIRED_PARAMS_HINT, | |
) |
if you had wanted to implement it this way.
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.
Excellent, I was looking for something like that and didn't see it. I'll look into that in this last round. Thanks!
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.
Thanks for making the changes!
Which issue(s) does this change fix?
#3193
Why is this change necessary?
As a few people mentioned in #3193, our API allows users to authenticate against our institution's local single-sign-on service. It has proven impractical to try to do rapid development and debugging using
sam sync
. We have been working around this by using an SSL proxy running in Docker (first usingnginx
and thenhaproxy
) to proxy connections fromhttps:3002
tohttp:3000
. Lately, even this workaround has started to introduce issues, as the proxies' own quirks have resulted in stripped response headers and failed rewrites.How does it address the issue?
It adds two new parameters,
--ssl-cert-file
and--ssl-key-file
, tosam local start-api
andstart-lambda
. (It was my intention only to add this functionality tostart-api
, but the CLI options for both are already defined in common, so it seemed easier just to go with it.) By default, without those parameters specified, the command behaves as it does now. With both specified, their values are passed through as a tuple to the Flask app, so it can start with a defined SSL context.What side effects does this change have?
None. Default behavior remains the same, and all new functionality is handled by Flask.
Mandatory Checklist
PRs will only be reviewed after checklist is complete
make pr
passesmake update-reproducible-reqs
if dependencies were changedsamcli.json
to include new CLI parameter specs, which I assume is all that's neededBy submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.