-
Notifications
You must be signed in to change notification settings - Fork 104
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
Require authentication for dry run function and run gcloud auth when … #5171
Conversation
a0627cc
to
fe03660
Compare
This comment has been minimized.
This comment has been minimized.
fe03660
to
19c024c
Compare
This comment has been minimized.
This comment has been minimized.
bigquery_etl/cli/utils.py
Outdated
try: | ||
subprocess.run(["gcloud", "auth", "application-default", "login"]) | ||
except Exception as e: | ||
print(f"Could not log in to GCP: {e}") | ||
return False |
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 will prompt the browser authentication flow
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 that
gcloud
command somehow ends up getting run in a non-interactive context (e.g. Airflow tasks, CI jobs) it seems like it could hang the process waiting for the browser-based auth to be completed, unless the command is smart enough to detect that it's running in a non-interactive context or the attempt to open a browser fails. Is there a reasonable way to guard against that (e.g. checking for particular environment variables)? - Even in an interactive context this could cause a headache if it gets called in a parallelized way (e.g. pytest, SQL generators), where it could spam open a bunch of browser windows. To guard against that I think we'd want to make sure authentication is triggered either prior to the parallelization starting, or in some controlled way (e.g. for pytest maybe using some scoped fixture?).
- While putting this logic into the
is_authenticated()
function is expedient, IMO it conflicts with the natural expectations people would have based on the function name that it's just a status check with no side effects. I'd suggest putting this logic in a new imperatively-named function likeauthenticate()
orensure_authenticated()
, which would raise an appropriate error if authentication fails. - It might be a good idea to cache this function (and/or the alternate imperative function if you go that route) to avoid the authentication getting checked repeatedly unnecessarily.
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.
Also, I believe check=True
needs to be specified for subprocess.run()
to raise an exception if the command exited with a non-zero exit code.
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.
Yeah, that's a good point. I don't see a reliable way to check for non-interactive environment. Perhaps for now it's best to not call gcloud auth
and print out an error and a suggestion to run authentication.
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 opened #5174 for now, to keep track of this. I think for now we just keep the flow as is, and ask users to run gcloud auth
themselves.
bigquery_etl/cli/utils.py
Outdated
@@ -44,7 +45,11 @@ def is_authenticated(): | |||
try: | |||
bigquery.Client(project="") |
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.
In testing this locally I didn't get prompted to authenticate because I did have application default credentials, but they were expired. I think an alternate approach is needed, like calling google.auth.default()
to get the credentials (which will also raise DefaultCredentialsError
if no default credentials were found) and then checking its valid
property.
bigquery_etl/cli/utils.py
Outdated
try: | ||
subprocess.run(["gcloud", "auth", "application-default", "login"]) | ||
except Exception as e: | ||
print(f"Could not log in to GCP: {e}") | ||
return False |
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 that
gcloud
command somehow ends up getting run in a non-interactive context (e.g. Airflow tasks, CI jobs) it seems like it could hang the process waiting for the browser-based auth to be completed, unless the command is smart enough to detect that it's running in a non-interactive context or the attempt to open a browser fails. Is there a reasonable way to guard against that (e.g. checking for particular environment variables)? - Even in an interactive context this could cause a headache if it gets called in a parallelized way (e.g. pytest, SQL generators), where it could spam open a bunch of browser windows. To guard against that I think we'd want to make sure authentication is triggered either prior to the parallelization starting, or in some controlled way (e.g. for pytest maybe using some scoped fixture?).
- While putting this logic into the
is_authenticated()
function is expedient, IMO it conflicts with the natural expectations people would have based on the function name that it's just a status check with no side effects. I'd suggest putting this logic in a new imperatively-named function likeauthenticate()
orensure_authenticated()
, which would raise an appropriate error if authentication fails. - It might be a good idea to cache this function (and/or the alternate imperative function if you go that route) to avoid the authentication getting checked repeatedly unnecessarily.
This comment has been minimized.
This comment has been minimized.
- sql/moz-fx-data-shared-prod/fenix_derived/ltv_state_values_v1/query.sql | ||
- sql/moz-fx-data-shared-prod/fenix_derived/ltv_state_values_v2/query.sql |
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.
As discussed in the Jira ticket, the dryrun service account won't have access to analysis
. These are the only two datasets atm that access an analysis
dataset. They'll get productionized soon, so until then skip dryruns.
This comment has been minimized.
This comment has been minimized.
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.
r+wc
- &skip_forked_pr | ||
run: | ||
name: Early return if this build is from a forked PR | ||
command: | | ||
if [ -n "$CIRCLE_PR_NUMBER" ]; then | ||
echo "Cannot pass creds to forked PRs," \ | ||
"so marking this step successful" | ||
circleci-agent step halt | ||
fi |
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.
The test-sql
and test-routines
jobs use similar forked-PR-detection logic. Should they use this instead?
- &authenticate | ||
run: | ||
name: Authenticate to GCP | ||
command: | | ||
export GOOGLE_APPLICATION_CREDENTIALS="/tmp/gcp.json" | ||
echo 'export GOOGLE_APPLICATION_CREDENTIALS="/tmp/gcp.json"' >> "$BASH_ENV" | ||
echo "$GCLOUD_SERVICE_KEY" > "$GOOGLE_APPLICATION_CREDENTIALS" |
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.
The test-sql
, integration
, and private-generate-sql
jobs don't set up authentication. Should they?
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.
private-generate-sql
does indeed need this. At least the current tests in integration
and test-sql
don't depend on dryruns. So they don't need to change
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.
At least the current tests in
integration
andtest-sql
don't depend on dryruns. So they don't need to change
But the test-sql
job has forked-PR-detection logic that says "Cannot pass creds to forked PRs". Is that referring to different credentials?
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.
Yeah, those are different credentials afaik. for running some of these SQL tests we write test data to a BigQuery test project that needs these credentials
bigquery_etl/dryrun.py
Outdated
|
||
if not is_authenticated(): | ||
print( | ||
"Authentication to GCP required. Run `gcloud auth login` " |
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 tested and verified that the specified gcloud auth login
command isn't sufficient without the additional --update-adc
argument.
"Authentication to GCP required. Run `gcloud auth login` " | |
"Authentication to GCP required. Run `gcloud auth login --update-adc` " |
(this exact same message is used in a bunch of other places, but updating all those is probably beyond the scope of this PR).
"Authentication to GCP required. Run `gcloud auth login` " | ||
"and check that the project is set correctly." | ||
) | ||
sys.exit(1) |
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.
Now that authentication is being required in many more cases, it might be good to update the "GCP CLI tools" section of the README to instruct non-DEs to authenticate.
This comment has been minimized.
This comment has been minimized.
6fba024
to
68ef6f5
Compare
This comment has been minimized.
This comment has been minimized.
Integration report for "Refactor skip_fork in CI, clarify login requirements"
|
#5171) * Require authentication for dry run function and run gcloud auth when not logged in * authenticate step in CI, remove interactive gcloud auth * Skip dryrun for ltv_state_values_v2 * Refactor skip_fork in CI, clarify login requirements
…not logged in
I opened https://mozilla-hub.atlassian.net/browse/DSRE-1558 to actually require authentication for the dryrun function and give dryrun permissions against restricted datasets. The PR should be merged before we apply these changes.
Fixes #5168
Checklist for reviewer:
<username>:<branch>
of the fork as parameter. The parameter will also show upin the logs of the
manual-trigger-required-for-fork
CI task together with more detailed instructions.For modifications to schemas in restricted namespaces (see
CODEOWNERS
):┆Issue is synchronized with this Jira Task