diff --git a/doc/man/s3fs.1 b/doc/man/s3fs.1 index a2e7d35d28..6ccff63a16 100644 --- a/doc/man/s3fs.1 +++ b/doc/man/s3fs.1 @@ -23,7 +23,7 @@ For unprivileged user. s3fs is a FUSE filesystem that allows you to mount an Amazon S3 bucket as a local filesystem. It stores files natively and transparently in S3 (i.e., you can use other programs to access the same files). .SH AUTHENTICATION s3fs supports the standard AWS credentials (filehttps://docs.aws.amazon.com/cli/latest/userguide/cli-config-files.html) stored in `${HOME}/.aws/credentials`. -Alternatively, s3fs supports a custom passwd file. +Alternatively, s3fs supports a custom passwd file. Only AWS credentials file format can be used when AWS session token is required. The s3fs password file has this format (use this format if you have only one set of credentials): .RS 4 \fBaccessKeyId\fP:\fBsecretAccessKey\fP diff --git a/src/curl.cpp b/src/curl.cpp index e1f68de51a..b8957fd556 100644 --- a/src/curl.cpp +++ b/src/curl.cpp @@ -385,6 +385,7 @@ int S3fsCurl::max_multireq = 20; // default off_t S3fsCurl::multipart_size = MULTIPART_SIZE; // default bool S3fsCurl::is_sigv4 = true; // default bool S3fsCurl::is_ua = true; // default +bool S3fsCurl::is_use_session_token = false; // default //------------------------------------------------------------------- // Class methods for S3fsCurl @@ -1194,6 +1195,20 @@ bool S3fsCurl::SetAccessKey(const char* AccessKeyId, const char* SecretAccessKey return true; } +bool S3fsCurl::SetAccessKeyWithSessionToken(const char* AccessKeyId, const char* SecretAccessKey, const char* SessionToken) +{ + bool access_key_is_empty = !AccessKeyId || '\0' == AccessKeyId[0]; + bool secret_access_key_is_empty = !SecretAccessKey || '\0' == SecretAccessKey[0]; + bool session_token_is_empty = !SessionToken || '\0' == SessionToken[0]; + if((!S3fsCurl::is_ibm_iam_auth && access_key_is_empty) || secret_access_key_is_empty || session_token_is_empty){ + return false; + } + AWSAccessKeyId = AccessKeyId; + AWSSecretAccessKey = SecretAccessKey; + AWSAccessToken = SessionToken; + return true; +} + long S3fsCurl::SetSslVerifyHostname(long value) { if(0 != value && 1 != value){ @@ -1211,6 +1226,13 @@ bool S3fsCurl::SetIsIBMIAMAuth(bool flag) return old; } +bool S3fsCurl::SetIsUseSessionToken(bool flag) +{ + bool old = S3fsCurl::is_use_session_token; + S3fsCurl::is_use_session_token = flag; + return old; +} + bool S3fsCurl::SetIsECS(bool flag) { bool old = S3fsCurl::is_ecs; @@ -2408,7 +2430,7 @@ string S3fsCurl::CalcSignatureV2(const string& method, const string& strMD5, con string Signature; string StringToSign; - if(!S3fsCurl::IAM_role.empty() || S3fsCurl::is_ecs){ + if(!S3fsCurl::IAM_role.empty() || S3fsCurl::is_ecs || S3fsCurl::is_use_session_token){ requestHeaders = curl_slist_sort_insert(requestHeaders, "x-amz-security-token", S3fsCurl::AWSAccessToken.c_str()); } @@ -2446,7 +2468,7 @@ string S3fsCurl::CalcSignature(const string& method, const string& canonical_uri string Signature, StringCQ, StringToSign; string uriencode; - if(!S3fsCurl::IAM_role.empty() || S3fsCurl::is_ecs){ + if(!S3fsCurl::IAM_role.empty() || S3fsCurl::is_ecs || S3fsCurl::is_use_session_token){ requestHeaders = curl_slist_sort_insert(requestHeaders, "x-amz-security-token", S3fsCurl::AWSAccessToken.c_str()); } diff --git a/src/curl.h b/src/curl.h index 10c6937f32..79018972f5 100644 --- a/src/curl.h +++ b/src/curl.h @@ -270,6 +270,7 @@ class S3fsCurl static std::string AWSAccessToken; static time_t AWSAccessTokenExpire; static bool is_ecs; + static bool is_use_session_token; static bool is_ibm_iam_auth; static std::string IAM_cred_url; static size_t IAM_field_count; @@ -428,6 +429,7 @@ class S3fsCurl static bool SetVerbose(bool flag); static bool GetVerbose(void) { return S3fsCurl::is_verbose; } static bool SetAccessKey(const char* AccessKeyId, const char* SecretAccessKey); + static bool SetAccessKeyWithSessionToken(const char* AccessKeyId, const char* SecretAccessKey, const char * SessionToken); static bool IsSetAccessKeyID(void){ return (0 < S3fsCurl::AWSAccessKeyId.size()); } @@ -443,6 +445,7 @@ class S3fsCurl static int SetMaxMultiRequest(int max); static int GetMaxMultiRequest(void) { return S3fsCurl::max_multireq; } static bool SetIsECS(bool flag); + static bool SetIsUseSessionToken(bool flag); static bool SetIsIBMIAMAuth(bool flag); static size_t SetIAMFieldCount(size_t field_count); static std::string SetIAMCredentialsURL(const char* url); diff --git a/src/s3fs.cpp b/src/s3fs.cpp index 527a85a411..1b7d475d1a 100644 --- a/src/s3fs.cpp +++ b/src/s3fs.cpp @@ -141,6 +141,7 @@ static bool is_remove_cache = false; static bool is_ecs = false; static bool is_ibm_iam_auth = false; static bool is_use_xattr = false; +static bool is_use_session_token = false; static bool create_bucket = false; static int64_t singlepart_copy_limit = 512 * 1024 * 1024; static bool is_specified_endpoint = false; @@ -4085,6 +4086,7 @@ static int read_aws_credentials_file(const std::string &filename) string profile; string accesskey; string secret; + string session_token; // read each line string line; @@ -4104,6 +4106,7 @@ static int read_aws_credentials_file(const std::string &filename) profile = line.substr(1, line.size() - 2); accesskey.clear(); secret.clear(); + session_token.clear(); } size_t pos = line.find_first_of('='); @@ -4116,16 +4119,26 @@ static int read_aws_credentials_file(const std::string &filename) accesskey = value; }else if(key == "aws_secret_access_key"){ secret = value; + }else if(key == "aws_session_token"){ + session_token = value; } } if(profile != aws_profile){ return EXIT_FAILURE; } - if(!S3fsCurl::SetAccessKey(accesskey.c_str(), secret.c_str())){ - S3FS_PRN_EXIT("failed to set internal data for access key/secret key from aws credential file."); - return EXIT_FAILURE; + if (session_token.empty()) { + if(!S3fsCurl::SetAccessKey(accesskey.c_str(), secret.c_str())){ + S3FS_PRN_EXIT("failed to set internal data for access key/secret key from aws credential file."); + return EXIT_FAILURE; + } + } else { + if (!S3fsCurl::SetAccessKeyWithSessionToken(accesskey.c_str(), secret.c_str(), session_token.c_str())) { + S3FS_PRN_EXIT("session token is invalid."); + return EXIT_FAILURE; + } } + return EXIT_SUCCESS; } @@ -4249,12 +4262,29 @@ static int get_access_keys() // 3 - environment variables char* AWSACCESSKEYID = getenv("AWSACCESSKEYID"); char* AWSSECRETACCESSKEY = getenv("AWSSECRETACCESSKEY"); + char* AWSSESSIONTOKEN = getenv("AWSSESSIONTOKEN"); if(AWSACCESSKEYID != NULL || AWSSECRETACCESSKEY != NULL){ if( (AWSACCESSKEYID == NULL && AWSSECRETACCESSKEY != NULL) || (AWSACCESSKEYID != NULL && AWSSECRETACCESSKEY == NULL) ){ S3FS_PRN_EXIT("if environment variable AWSACCESSKEYID is set then AWSSECRETACCESSKEY must be set too."); return EXIT_FAILURE; } + S3FS_PRN_INFO2("access key from env variables"); + if (AWSSESSIONTOKEN != NULL) { + S3FS_PRN_INFO2("session token is available"); + is_use_session_token = true; + S3fsCurl::SetIsUseSessionToken(true); + if (!S3fsCurl::SetAccessKeyWithSessionToken(AWSACCESSKEYID, AWSSECRETACCESSKEY, AWSSESSIONTOKEN)) { + S3FS_PRN_EXIT("session token is invalid."); + return EXIT_FAILURE; + } + } else { + S3FS_PRN_INFO2("session token is not available"); + if (is_use_session_token) { + S3FS_PRN_EXIT("environment variable AWSSESSIONTOKEN is expected to be set."); + return EXIT_FAILURE; + } + } if(!S3fsCurl::SetAccessKey(AWSACCESSKEYID, AWSSECRETACCESSKEY)){ S3FS_PRN_EXIT("if one access key is specified, both keys need to be specified."); return EXIT_FAILURE; @@ -4680,6 +4710,10 @@ static int my_fuse_opt_proc(void* data, const char* arg, int key, struct fuse_ar is_ibm_iam_auth = true; return 0; } + if (0 == STR2NCMP(arg, "use_session_token")) { + S3fsCurl::SetIsUseSessionToken(true); + is_use_session_token = true; + } if(0 == STR2NCMP(arg, "ibm_iam_endpoint=")){ std::string endpoint_url; std::string iam_endpoint = strchr(arg, '=') + sizeof(char); diff --git a/src/s3fs_util.cpp b/src/s3fs_util.cpp index 139073f01b..047252da0b 100644 --- a/src/s3fs_util.cpp +++ b/src/s3fs_util.cpp @@ -1329,6 +1329,11 @@ void show_help () " Unicode set.\n" " Useful on clients not using utf-8 as their file system encoding.\n" "\n" + " use_session_token - indicate that session token should be provided.\n" + " If credentials are provided by environment variables this switch\n" + " forces presence check of AWSSESSIONTOKEN variable.\n" + " Otherwise ane error is returned." + "\n" "FUSE/mount Options:\n" "\n" " Most of the generic mount options described in 'man mount' are\n"