Skip to content

SNOW-1902244: Workflow identity federation attestations #871

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

Merged
merged 11 commits into from
Apr 22, 2025

Conversation

sfc-gh-jszczerbinski
Copy link
Collaborator

@sfc-gh-jszczerbinski sfc-gh-jszczerbinski commented Apr 9, 2025

Adds Workflow identity federation attestations for AWS, Azure, GCP and OIDC

@sfc-gh-jszczerbinski sfc-gh-jszczerbinski force-pushed the SNOW-1902244-odbc-csp-in-driver branch from 74fa2a6 to 3b1aba1 Compare April 11, 2025 08:55
@sfc-gh-jszczerbinski sfc-gh-jszczerbinski marked this pull request as ready for review April 15, 2025 09:07
@sfc-gh-jszczerbinski sfc-gh-jszczerbinski requested a review from a team as a code owner April 15, 2025 09:07
@sfc-gh-jszczerbinski sfc-gh-jszczerbinski force-pushed the SNOW-1902244-odbc-csp-in-driver branch from eca7ee8 to 5c4618c Compare April 16, 2025 08:14
@sfc-gh-jszczerbinski sfc-gh-jszczerbinski changed the title Workflow identity federation attestations SNOW-1902244: Workflow identity federation attestations Apr 16, 2025
@sfc-gh-jszczerbinski sfc-gh-jszczerbinski force-pushed the SNOW-1902244-odbc-csp-in-driver branch from 82f9e4b to 3593e97 Compare April 17, 2025 08:19
}

auto request = Aws::Http::CreateHttpRequest(
Aws::String("https://sts.us-west-2.amazonaws.com/?Action=GetCallerIdentity&Version=2011-06-15"),
Copy link
Contributor

Choose a reason for hiding this comment

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

should it always be us-west-2?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Fixed

return Attestation{AttestationType::AWS, base64};
}


Copy link
Contributor

Choose a reason for hiding this comment

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

🧐 random empty lines

std::string err = picojson::parse(json, response_body);
if (!err.empty()) {
CXX_LOG_ERROR("Error parsing Azure response: %s", err.c_str());
return Attestation{AttestationType::AZURE, ""};
Copy link
Contributor

Choose a reason for hiding this comment

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

does boost::none mean error connecting to csp while Attestation with empty credentials means csp side issue?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

This should return boost::none here, it's a refactor leftover.

}

boost::url AzureAttestationConfig::getRequestURL() const {
boost::urls::url url = boost::url("http://169.254.169.254/metadata/identity/oauth2/token");
Copy link
Contributor

Choose a reason for hiding this comment

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

Could we hide this ip behind some constant like CSP_METADATA_SERVICE_IP to make it less scary?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Yes, but this well known ip. I think the code is more readable this way as this IP is well known.

boost::optional<Attestation> createOIDCAttestation(const AttestationConfig& config) {
if (!config.token) {
CXX_LOG_WARN("No token provided for OIDC attestation.");
return {};
Copy link
Contributor

Choose a reason for hiding this comment

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

sometimes we return {} and sometimes boost:none, let's commit to one option

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Changing to boost::none for clarity

Copy link

codecov bot commented Apr 17, 2025

Codecov Report

Attention: Patch coverage is 37.29508% with 153 lines in your changes missing coverage. Please review.

Project coverage is 78.10%. Comparing base (68b2501) to head (d94ed3e).

Files with missing lines Patch % Lines
cpp/AwsAttestation.cpp 0.00% 32 Missing ⚠️
cpp/http/HttpClient.cpp 9.37% 29 Missing ⚠️
cpp/AzureAttestation.cpp 62.50% 27 Missing ⚠️
cpp/WifAttestation.cpp 36.66% 19 Missing ⚠️
cpp/AWSUtils.cpp 44.82% 16 Missing ⚠️
cpp/GcpAttestation.cpp 62.96% 10 Missing ⚠️
include/snowflake/HttpClient.hpp 9.09% 10 Missing ⚠️
include/snowflake/WifAttestation.hpp 0.00% 10 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master     #871      +/-   ##
==========================================
- Coverage   80.61%   78.10%   -2.52%     
==========================================
  Files         117      125       +8     
  Lines       10463    10683     +220     
==========================================
- Hits         8435     8344      -91     
- Misses       2028     2339     +311     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

}

std::string region = getAwsRegion();
std::string host = std::string("sts.") + getAwsRegion() + ".amazonaws.com";
Copy link
Collaborator

Choose a reason for hiding this comment

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

Don't we want to use SnowflakeS3Client::getDomainSuffixForRegionalUrl here?

);

request->SetHeaderValue("Host", host);
request->SetHeaderValue("X-Snowflake-Audience", "snowflakecomputing.com");
Copy link
Collaborator

Choose a reason for hiding this comment

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

What about .cn?

std::string json = picojson::value(obj).serialize(true);
std::string base64;
Util::Base64::encodePadding(json.begin(), json.end(), std::back_inserter(base64));
Aws::ShutdownAPI(options);
Copy link
Collaborator

Choose a reason for hiding this comment

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

Maybe it would be better to integrate aws init and shutdown with awsdk_init struct?

CXX_LOG_INFO("Running request: %s", req.url.c_str());
CXX_LOG_INFO("Method: %s", HttpRequest::methodToString(req.method).c_str());
for (const auto &h: req.headers) {
CXX_LOG_INFO("Header: %s: %s", h.first.c_str(), h.second.c_str());
Copy link
Collaborator

Choose a reason for hiding this comment

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

Is it OK to log all headers on INFO level? What about secrets?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Those were development prints i forgot to delete.


private:
static size_t write(void *ptr, size_t size, size_t nmemb, HttpResponse *response) {
CXX_LOG_INFO("Writing %d bytes", (int) (size * nmemb));
Copy link
Collaborator

Choose a reason for hiding this comment

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

It's rather debug or trace level.

private:
static size_t write(void *ptr, size_t size, size_t nmemb, HttpResponse *response) {
CXX_LOG_INFO("Writing %d bytes", (int) (size * nmemb));
response->m_buffer.insert(response->m_buffer.end(), (char *) ptr, (char *) ptr + size * nmemb);
Copy link
Collaborator

Choose a reason for hiding this comment

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

I think HttpResponse should be responsible for writing to m_buffer. Maybe whole method write should be there as well?

Copy link
Collaborator Author

@sfc-gh-jszczerbinski sfc-gh-jszczerbinski Apr 18, 2025

Choose a reason for hiding this comment

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

This write method is implementation specific (for curl) if I used other http library it would not exist. I would like to keep it within a curl client implementation.

namespace Snowflake {
namespace Client {
struct HttpResponse {
long code;
Copy link
Collaborator

Choose a reason for hiding this comment

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

m_code? or buffer

int main()
{
const struct CMUnitTest tests[] = {
#ifndef _WIN32
Copy link
Collaborator

Choose a reason for hiding this comment

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

Why? A comment would be nice.

@sfc-gh-jszczerbinski sfc-gh-jszczerbinski merged commit 478b08b into master Apr 22, 2025
47 of 51 checks passed
@sfc-gh-jszczerbinski sfc-gh-jszczerbinski deleted the SNOW-1902244-odbc-csp-in-driver branch April 22, 2025 08:33
@github-actions github-actions bot locked and limited conversation to collaborators Apr 22, 2025
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants