1
1
Fork 0
mirror of https://github.com/NixOS/nix.git synced 2025-11-09 03:56:01 +01:00

Merge pull request #14206 from lovesegfault/curl-based-s3-pieces

feat(libstore): add builtin fetchurl S3 credential pre-resolution
This commit is contained in:
Sergei Zimmerman 2025-10-14 20:10:41 +00:00 committed by GitHub
commit 4041bfdb40
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 97 additions and 5 deletions

View file

@ -33,6 +33,7 @@ static void builtinFetchurl(const BuiltinBuilderContext & ctx)
/* Note: have to use a fresh fileTransfer here because we're in /* Note: have to use a fresh fileTransfer here because we're in
a forked process. */ a forked process. */
debug("[pid=%d] builtin:fetchurl creating fresh FileTransfer instance", getpid());
auto fileTransfer = makeFileTransfer(); auto fileTransfer = makeFileTransfer();
auto fetch = [&](const std::string & url) { auto fetch = [&](const std::string & url) {
@ -40,6 +41,18 @@ static void builtinFetchurl(const BuiltinBuilderContext & ctx)
FileTransferRequest request(VerbatimURL{url}); FileTransferRequest request(VerbatimURL{url});
request.decompress = false; request.decompress = false;
#if NIX_WITH_CURL_S3
// Use pre-resolved credentials if available
if (ctx.awsCredentials && request.uri.scheme() == "s3") {
debug("[pid=%d] Using pre-resolved AWS credentials from parent process", getpid());
request.usernameAuth = UsernameAuth{
.username = ctx.awsCredentials->accessKeyId,
.password = ctx.awsCredentials->secretAccessKey,
};
request.preResolvedAwsSessionToken = ctx.awsCredentials->sessionToken;
}
#endif
auto decompressor = makeDecompressionSink(unpack && hasSuffix(mainUrl, ".xz") ? "xz" : "none", sink); auto decompressor = makeDecompressionSink(unpack && hasSuffix(mainUrl, ".xz") ? "xz" : "none", sink);
fileTransfer->download(std::move(request), *decompressor); fileTransfer->download(std::move(request), *decompressor);
decompressor->finish(); decompressor->finish();

View file

@ -2,6 +2,11 @@
///@file ///@file
#include "nix/store/derivations.hh" #include "nix/store/derivations.hh"
#include "nix/store/config.hh"
#if NIX_WITH_CURL_S3
# include "nix/store/aws-creds.hh"
#endif
namespace nix { namespace nix {
@ -12,6 +17,14 @@ struct BuiltinBuilderContext
std::string netrcData; std::string netrcData;
std::string caFileData; std::string caFileData;
Path tmpDirInSandbox; Path tmpDirInSandbox;
#if NIX_WITH_CURL_S3
/**
* Pre-resolved AWS credentials for S3 URLs in builtin:fetchurl.
* When present, these should be used instead of creating new credential providers.
*/
std::optional<AwsCredentials> awsCredentials;
#endif
}; };
using BuiltinBuilder = std::function<void(const BuiltinBuilderContext &)>; using BuiltinBuilder = std::function<void(const BuiltinBuilderContext &)>;

View file

@ -46,6 +46,12 @@
#include "store-config-private.hh" #include "store-config-private.hh"
#include "build/derivation-check.hh" #include "build/derivation-check.hh"
#if NIX_WITH_CURL_S3
# include "nix/store/aws-creds.hh"
# include "nix/store/s3-url.hh"
# include "nix/util/url.hh"
#endif
namespace nix { namespace nix {
struct NotDeterministic : BuildError struct NotDeterministic : BuildError
@ -290,6 +296,15 @@ protected:
*/ */
virtual void startChild(); virtual void startChild();
#if NIX_WITH_CURL_S3
/**
* Pre-resolve AWS credentials for S3 URLs in builtin:fetchurl.
* This should be called before forking to ensure credentials are available in child.
* Returns the credentials if successfully resolved, or std::nullopt otherwise.
*/
std::optional<AwsCredentials> preResolveAwsCredentials();
#endif
private: private:
/** /**
@ -339,10 +354,20 @@ protected:
*/ */
void writeBuilderFile(const std::string & name, std::string_view contents); void writeBuilderFile(const std::string & name, std::string_view contents);
/**
* Arguments passed to runChild().
*/
struct RunChildArgs
{
#if NIX_WITH_CURL_S3
std::optional<AwsCredentials> awsCredentials;
#endif
};
/** /**
* Run the builder's process. * Run the builder's process.
*/ */
void runChild(); void runChild(RunChildArgs args);
/** /**
* Move the current process into the chroot, if any. Called early * Move the current process into the chroot, if any. Called early
@ -920,11 +945,43 @@ void DerivationBuilderImpl::openSlave()
throw SysError("cannot pipe standard error into log file"); throw SysError("cannot pipe standard error into log file");
} }
#if NIX_WITH_CURL_S3
std::optional<AwsCredentials> DerivationBuilderImpl::preResolveAwsCredentials()
{
if (drv.isBuiltin() && drv.builder == "builtin:fetchurl") {
auto url = drv.env.find("url");
if (url != drv.env.end()) {
try {
auto parsedUrl = parseURL(url->second);
if (parsedUrl.scheme == "s3") {
debug("Pre-resolving AWS credentials for S3 URL in builtin:fetchurl");
auto s3Url = ParsedS3URL::parse(parsedUrl);
// Use the preResolveAwsCredentials from aws-creds
auto credentials = nix::preResolveAwsCredentials(s3Url);
debug("Successfully pre-resolved AWS credentials in parent process");
return credentials;
}
} catch (const std::exception & e) {
debug("Error pre-resolving S3 credentials: %s", e.what());
}
}
}
return std::nullopt;
}
#endif
void DerivationBuilderImpl::startChild() void DerivationBuilderImpl::startChild()
{ {
pid = startProcess([&]() { RunChildArgs args{
#if NIX_WITH_CURL_S3
.awsCredentials = preResolveAwsCredentials(),
#endif
};
pid = startProcess([this, args = std::move(args)]() {
openSlave(); openSlave();
runChild(); runChild(std::move(args));
}); });
} }
@ -1181,7 +1238,7 @@ void DerivationBuilderImpl::writeBuilderFile(const std::string & name, std::stri
chownToBuilder(fd.get(), path); chownToBuilder(fd.get(), path);
} }
void DerivationBuilderImpl::runChild() void DerivationBuilderImpl::runChild(RunChildArgs args)
{ {
/* Warning: in the child we should absolutely not make any SQLite /* Warning: in the child we should absolutely not make any SQLite
calls! */ calls! */
@ -1198,6 +1255,9 @@ void DerivationBuilderImpl::runChild()
BuiltinBuilderContext ctx{ BuiltinBuilderContext ctx{
.drv = drv, .drv = drv,
.tmpDirInSandbox = tmpDirInSandbox(), .tmpDirInSandbox = tmpDirInSandbox(),
#if NIX_WITH_CURL_S3
.awsCredentials = args.awsCredentials,
#endif
}; };
if (drv.isBuiltin() && drv.builder == "builtin:fetchurl") { if (drv.isBuiltin() && drv.builder == "builtin:fetchurl") {

View file

@ -276,6 +276,12 @@ struct ChrootLinuxDerivationBuilder : ChrootDerivationBuilder, LinuxDerivationBu
void startChild() override void startChild() override
{ {
RunChildArgs args{
# if NIX_WITH_CURL_S3
.awsCredentials = preResolveAwsCredentials(),
# endif
};
/* Set up private namespaces for the build: /* Set up private namespaces for the build:
- The PID namespace causes the build to start as PID 1. - The PID namespace causes the build to start as PID 1.
@ -343,7 +349,7 @@ struct ChrootLinuxDerivationBuilder : ChrootDerivationBuilder, LinuxDerivationBu
if (usingUserNamespace) if (usingUserNamespace)
options.cloneFlags |= CLONE_NEWUSER; options.cloneFlags |= CLONE_NEWUSER;
pid_t child = startProcess([&]() { runChild(); }, options); pid_t child = startProcess([this, args = std::move(args)]() { runChild(std::move(args)); }, options);
writeFull(sendPid.writeSide.get(), fmt("%d\n", child)); writeFull(sendPid.writeSide.get(), fmt("%d\n", child));
_exit(0); _exit(0);