1
1
Fork 0
mirror of https://github.com/NixOS/nix.git synced 2025-11-08 19:46:02 +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
a forked process. */
debug("[pid=%d] builtin:fetchurl creating fresh FileTransfer instance", getpid());
auto fileTransfer = makeFileTransfer();
auto fetch = [&](const std::string & url) {
@ -40,6 +41,18 @@ static void builtinFetchurl(const BuiltinBuilderContext & ctx)
FileTransferRequest request(VerbatimURL{url});
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);
fileTransfer->download(std::move(request), *decompressor);
decompressor->finish();

View file

@ -2,6 +2,11 @@
///@file
#include "nix/store/derivations.hh"
#include "nix/store/config.hh"
#if NIX_WITH_CURL_S3
# include "nix/store/aws-creds.hh"
#endif
namespace nix {
@ -12,6 +17,14 @@ struct BuiltinBuilderContext
std::string netrcData;
std::string caFileData;
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 &)>;

View file

@ -46,6 +46,12 @@
#include "store-config-private.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 {
struct NotDeterministic : BuildError
@ -290,6 +296,15 @@ protected:
*/
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:
/**
@ -339,10 +354,20 @@ protected:
*/
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.
*/
void runChild();
void runChild(RunChildArgs args);
/**
* 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");
}
#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()
{
pid = startProcess([&]() {
RunChildArgs args{
#if NIX_WITH_CURL_S3
.awsCredentials = preResolveAwsCredentials(),
#endif
};
pid = startProcess([this, args = std::move(args)]() {
openSlave();
runChild();
runChild(std::move(args));
});
}
@ -1181,7 +1238,7 @@ void DerivationBuilderImpl::writeBuilderFile(const std::string & name, std::stri
chownToBuilder(fd.get(), path);
}
void DerivationBuilderImpl::runChild()
void DerivationBuilderImpl::runChild(RunChildArgs args)
{
/* Warning: in the child we should absolutely not make any SQLite
calls! */
@ -1198,6 +1255,9 @@ void DerivationBuilderImpl::runChild()
BuiltinBuilderContext ctx{
.drv = drv,
.tmpDirInSandbox = tmpDirInSandbox(),
#if NIX_WITH_CURL_S3
.awsCredentials = args.awsCredentials,
#endif
};
if (drv.isBuiltin() && drv.builder == "builtin:fetchurl") {

View file

@ -276,6 +276,12 @@ struct ChrootLinuxDerivationBuilder : ChrootDerivationBuilder, LinuxDerivationBu
void startChild() override
{
RunChildArgs args{
# if NIX_WITH_CURL_S3
.awsCredentials = preResolveAwsCredentials(),
# endif
};
/* Set up private namespaces for the build:
- The PID namespace causes the build to start as PID 1.
@ -343,7 +349,7 @@ struct ChrootLinuxDerivationBuilder : ChrootDerivationBuilder, LinuxDerivationBu
if (usingUserNamespace)
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));
_exit(0);