@@ -48,18 +48,56 @@ impl S3RemoteFs {
4848 bucket_name : String ,
4949 sub_path : Option < String > ,
5050 ) -> Result < Arc < Self > , CubeError > {
51- // Incorrect naming for ENV variables...
52- let access_key = env:: var ( "CUBESTORE_AWS_ACCESS_KEY_ID" ) . ok ( ) ;
53- let secret_key = env:: var ( "CUBESTORE_AWS_SECRET_ACCESS_KEY" ) . ok ( ) ;
54-
51+ let role_name = env:: var ( "CUBESTORE_AWS_IAM_ROLE" ) . ok ( ) ;
52+ let ( access_key, secret_key) = match role_name {
53+ Some ( role_name) => {
54+ let region = env:: var ( "CUBESTORE_AWS_REGION" ) . expect ( "CUBESTORE_AWS_REGION must be set" ) ;
55+ let account_id = Command :: new ( "aws" )
56+ . args ( & [ "sts" , "get-caller-identity" , "--query" , "Account" , "--output" , "text" ] )
57+ . output ( )
58+ . expect ( "Failed to get account ID" )
59+ . stdout
60+ . trim ( )
61+ . to_string ( ) ;
62+
63+ let assume_role_output = Command :: new ( "aws" )
64+ . args ( & [
65+ "sts" ,
66+ "assume-role" ,
67+ "--role-arn" ,
68+ & format ! ( "arn:aws:iam::{}:role/{}" , account_id, role_name) ,
69+ "--role-session-name" ,
70+ & format ! ( "session-{}" , role_name) ,
71+ "--query" ,
72+ "Credentials" ,
73+ "--output" ,
74+ "text" ,
75+ ] )
76+ . output ( )
77+ . expect ( "Failed to assume role" )
78+ . stdout
79+ . trim ( )
80+ . to_string ( ) ;
81+
82+ let access_key = assume_role_output. split_whitespace ( ) . nth ( 1 ) . unwrap ( ) . trim_matches ( '"' ) ;
83+ let secret_key = assume_role_output. split_whitespace ( ) . nth ( 3 ) . unwrap ( ) . trim_matches ( '"' ) ;
84+
85+ ( Some ( access_key) , Some ( secret_key) )
86+ }
87+ None => (
88+ env:: var ( "CUBESTORE_AWS_ACCESS_KEY_ID" ) . ok ( ) ,
89+ env:: var ( "CUBESTORE_AWS_SECRET_ACCESS_KEY" ) . ok ( ) ,
90+ ) ,
91+ } ;
92+
5593 let credentials = Credentials :: new (
5694 access_key. as_deref ( ) ,
5795 secret_key. as_deref ( ) ,
5896 None ,
5997 None ,
6098 None ,
6199 )
62- . map_err ( |err| {
100+ . map_err ( |err| {
63101 CubeError :: internal ( format ! (
64102 "Failed to create S3 credentials: {}" ,
65103 err. to_string( )
@@ -79,15 +117,22 @@ impl S3RemoteFs {
79117 sub_path,
80118 delete_mut : Mutex :: new ( ( ) ) ,
81119 } ) ;
82- spawn_creds_refresh_loop ( access_key, secret_key, bucket_name, region, & fs) ;
83-
120+
121+ spawn_creds_refresh_loop (
122+ role_name. or ( access_key. clone ( ) ) ,
123+ role_name. is_some ( ) ,
124+ bucket_name,
125+ region,
126+ & fs,
127+ ) ;
128+
84129 Ok ( fs)
85130 }
86131}
87132
88133fn spawn_creds_refresh_loop (
89- access_key : Option < String > ,
90- secret_key : Option < String > ,
134+ role_or_access_key : Option < String > ,
135+ is_role : bool ,
91136 bucket_name : String ,
92137 region : Region ,
93138 fs : & Arc < S3RemoteFs > ,
@@ -110,6 +155,43 @@ fn spawn_creds_refresh_loop(
110155 }
111156 Some ( fs) => fs,
112157 } ;
158+ let ( access_key, secret_key) = if is_role {
159+ let region = env:: var ( "CUBESTORE_AWS_REGION" ) . expect ( "CUBESTORE_AWS_REGION must be set" ) ;
160+ let account_id = Command :: new ( "aws" )
161+ . args ( & [ "sts" , "get-caller-identity" , "--query" , "Account" , "--output" , "text" ] )
162+ . output ( )
163+ . expect ( "Failed to get account ID" )
164+ . stdout
165+ . trim ( )
166+ . to_string ( ) ;
167+
168+ let assume_role_output = Command :: new ( "aws" )
169+ . args ( & [
170+ "sts" ,
171+ "assume-role" ,
172+ "--role-arn" ,
173+ & format ! ( "arn:aws:iam::{}:role/{}" , account_id, role_or_access_key. as_ref( ) . unwrap( ) ) ,
174+ "--role-session-name" ,
175+ & format ! ( "session-{}" , role_or_access_key. as_ref( ) . unwrap( ) ) ,
176+ "--query" ,
177+ "Credentials" ,
178+ "--output" ,
179+ "text" ,
180+ ] )
181+ . output ( )
182+ . expect ( "Failed to assume role" )
183+ . stdout
184+ . trim ( )
185+ . to_string ( ) ;
186+
187+ let access_key = assume_role_output. split_whitespace ( ) . nth ( 1 ) . unwrap ( ) . trim_matches ( '"' ) ;
188+ let secret_key = assume_role_output. split_whitespace ( ) . nth ( 3 ) . unwrap ( ) . trim_matches ( '"' ) ;
189+
190+ ( Some ( access_key) , Some ( secret_key) )
191+ } else {
192+ ( role_or_access_key, None )
193+ } ;
194+
113195 let c = match Credentials :: new (
114196 access_key. as_deref ( ) ,
115197 secret_key. as_deref ( ) ,
@@ -138,12 +220,24 @@ fn spawn_creds_refresh_loop(
138220
139221fn refresh_interval_from_env ( ) -> Duration {
140222 let mut mins = 180 ; // 3 hours by default.
141- if let Ok ( s) = std:: env:: var ( "CUBESTORE_AWS_CREDS_REFRESH_EVERY_MINS" ) {
142- match s. parse :: < u64 > ( ) {
143- Ok ( i) => mins = i,
144- Err ( e) => log:: error!( "Could not parse CUBESTORE_AWS_CREDS_REFRESH_EVERY_MINS. Refreshing every {} minutes. Error: {}" , mins, e) ,
223+ if let Ok ( _) = std:: env:: var ( "CUBESTORE_AWS_IAM_ROLE" ) {
224+ if let Ok ( s) = std:: env:: var ( "CUBESTORE_AWS_IAM_REFRESH_EVERY_MINS" ) {
225+ // 14 mins by default if IAM role present
226+ match s. parse :: < u64 > ( ) {
227+ Ok ( i) => mins = i,
228+ Err ( e) => log:: error!( "Could not parse CUBESTORE_AWS_IAM_REFRESH_EVERY_MINS. Refreshing every {} minutes. Error: {}" , mins, e) ,
229+ } ;
230+ } else {
231+ mins = 14 ;
232+ }
233+ } else {
234+ if let Ok ( s) = std:: env:: var ( "CUBESTORE_AWS_CREDS_REFRESH_EVERY_MINS" ) {
235+ match s. parse :: < u64 > ( ) {
236+ Ok ( i) => mins = i,
237+ Err ( e) => log:: error!( "Could not parse CUBESTORE_AWS_CREDS_REFRESH_EVERY_MINS. Refreshing every {} minutes. Error: {}" , mins, e) ,
238+ } ;
145239 } ;
146- } ;
240+ }
147241 Duration :: from_secs ( 60 * mins)
148242}
149243
0 commit comments