mirror of
https://github.com/chanzuckerberg/cellxgene.git
synced 2026-09-27 06:38:12 +08:00
Provide a hook into the AWS Secret Manager for the flask secret key (#1398)
Also, the secret manager required a region name, so there was some refactoring around how regions are handled. Fixes #1239
This commit is contained in:
+21
-4
@@ -93,8 +93,23 @@ There are many more options to these commands that may be important or necessary
|
||||
```
|
||||
$ make build
|
||||
```
|
||||
|
||||
6. Flask secret key
|
||||
|
||||
The application requires as secret key to be provided to flask, the web framework used by cellxgene.
|
||||
There are three ways to provide the secret key:
|
||||
|
||||
6. Create an environment
|
||||
- In the configuration file: update the server/flask_secret_key attribute.
|
||||
- An environment variable: CXG_SECRET_KEY
|
||||
- Managed by the AWS Secret Manager
|
||||
|
||||
If using the AWS Secret Manager, then the secret name is passed as an environment variable: CXG_AWS_SECRET_NAME.
|
||||
The secret must contain a key with the name "flask_secret_key".
|
||||
Likely you have located the AWS Secret Manager in the same AWS region as the dataroot. If that is not the case
|
||||
then the AWS Secret Manager region name can be specified in an environment variable: CXG_AWS_SECRET_REGION_NAME.
|
||||
|
||||
|
||||
7. Create an environment
|
||||
|
||||
```
|
||||
# name of the environment
|
||||
@@ -106,23 +121,25 @@ There are many more options to these commands that may be important or necessary
|
||||
# One or both of the following environment variables needs to be set
|
||||
$ CXG_DATAROOT=<location to your S3 bucket>
|
||||
$ CXG_CONFIG_FILE=<location to your config file>
|
||||
|
||||
# Potentially also set envvars for the sercret key.
|
||||
|
||||
$ eb create $EB_ENV --instance-type $EB_INSTANCE \
|
||||
--envvars CXG_DATAROOT=$CXG_DATAROOT,CXG_CONFIG_FILE=$CXG_CONFIG_FILE
|
||||
```
|
||||
|
||||
7. Give the elastic beanstalk environment access to the S3 bucket.
|
||||
8. Give the elastic beanstalk environment access to the S3 bucket.
|
||||
|
||||
This link may provide some useful information:
|
||||
https://aws.amazon.com/premiumsupport/knowledge-center/elastic-beanstalk-s3-bucket-instance/
|
||||
|
||||
8. Deploy the application
|
||||
9. Deploy the application
|
||||
|
||||
```
|
||||
$ eb deploy $EB_ENV
|
||||
```
|
||||
|
||||
9. Open the application in a browser
|
||||
10. Open the application in a browser
|
||||
|
||||
```
|
||||
$ eb open $EB_ENV
|
||||
|
||||
+40
-3
@@ -4,6 +4,8 @@ import sys
|
||||
import os
|
||||
import logging
|
||||
from flask_talisman import Talisman
|
||||
import boto3
|
||||
import json
|
||||
|
||||
if os.path.isdir("/opt/python/log"):
|
||||
# This is the standard location where Amazon EC2 instances store the application logs.
|
||||
@@ -23,12 +25,34 @@ sys.path.append(SERVERDIR)
|
||||
try:
|
||||
from server.common.app_config import AppConfig
|
||||
from server.app.app import Server
|
||||
from server.common.data_locator import DataLocator
|
||||
from server.common.data_locator import DataLocator, discover_s3_region_name
|
||||
except Exception:
|
||||
logging.critical("Exception importing server modules", exc_info=True)
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def get_flask_secret_key(region_name, secret_name):
|
||||
session = boto3.session.Session()
|
||||
client = session.client(
|
||||
service_name='secretsmanager',
|
||||
region_name=region_name
|
||||
)
|
||||
|
||||
try:
|
||||
get_secret_value_response = client.get_secret_value(
|
||||
SecretId=secret_name
|
||||
)
|
||||
if 'SecretString' in get_secret_value_response:
|
||||
var = get_secret_value_response['SecretString']
|
||||
secret = json.loads(var)
|
||||
return secret.get("flask_secret_key")
|
||||
except Exception:
|
||||
logging.critical("Caught exception during get_secret_key", exc_info=True)
|
||||
sys.exit(1)
|
||||
|
||||
return None
|
||||
|
||||
|
||||
class WSGIServer(Server):
|
||||
def __init__(self, app_config):
|
||||
super().__init__(app_config)
|
||||
@@ -44,8 +68,12 @@ try:
|
||||
dataroot = os.getenv("CXG_DATAROOT")
|
||||
config_file = os.getenv("CXG_CONFIG_FILE")
|
||||
|
||||
secret_name = os.getenv("CXG_AWS_SECRET_NAME")
|
||||
secret_region_name = os.getenv("CXG_AWS_SECRET_REGION_NAME")
|
||||
|
||||
if config_file:
|
||||
config_location = DataLocator(config_file)
|
||||
region_name = discover_s3_region_name(config_file)
|
||||
config_location = DataLocator(config_file, region_name)
|
||||
if config_location.exists():
|
||||
with config_location.local_handle() as lh:
|
||||
logging.info(f"Configuration from {config_file}")
|
||||
@@ -66,6 +94,14 @@ try:
|
||||
logging.info(f"Configuration from CXG_DATAROOT")
|
||||
app_config.update(multi_dataset__dataroot=dataroot)
|
||||
|
||||
if secret_name:
|
||||
if secret_region_name is None:
|
||||
secret_region_name = discover_s3_region_name(app_config.multi_dataset__dataroot)
|
||||
if not secret_region_name:
|
||||
logging.error(f"Expected to discover the s3 region name from {app_config.multi_dataset__dataroot}")
|
||||
flask_secret_key = get_flask_secret_key(secret_region_name, secret_name)
|
||||
app_config.update(server__flask_secret_key=flask_secret_key)
|
||||
|
||||
# features are unsupported in the current hosted server
|
||||
app_config.update(
|
||||
user_annotations__enable=False,
|
||||
@@ -77,7 +113,8 @@ try:
|
||||
|
||||
if not app_config.server__flask_secret_key:
|
||||
logging.critical(
|
||||
f"flask_secret_key is not provided. Either set in config file, or in CXG_SECRET_KEY environment variable"
|
||||
f"flask_secret_key is not provided. Either set in config file, CXG_SECRET_KEY environment variable, "
|
||||
"or in AWS Secret Manager"
|
||||
)
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user