@@ -32,8 +32,10 @@ use object_store::{ClientOptions, ObjectStore, PutPayload};
3232use relative_path:: { RelativePath , RelativePathBuf } ;
3333
3434use std:: collections:: BTreeMap ;
35+ use std:: fmt:: Display ;
3536use std:: iter:: Iterator ;
3637use std:: path:: Path as StdPath ;
38+ use std:: str:: FromStr ;
3739use std:: sync:: Arc ;
3840use std:: time:: { Duration , Instant } ;
3941
@@ -84,6 +86,16 @@ pub struct S3Config {
8486 #[ arg( long, env = "P_S3_BUCKET" , value_name = "bucket-name" , required = true ) ]
8587 pub bucket_name : String ,
8688
89+ /// Server side encryption to use for operations with objects.
90+ /// Currently, this only supports SSE-C. Value should be
91+ /// like SSE-C:AES256:<base64_encoded_encryption_key>.
92+ #[ arg(
93+ long,
94+ env = "P_S3_SSEC_ENCRYPTION_KEY" ,
95+ value_name = "ssec-encryption-key"
96+ ) ]
97+ pub ssec_encryption_key : Option < SSECEncryptionKey > ,
98+
8799 /// Set client to send checksum header on every put request
88100 #[ arg(
89101 long,
@@ -130,6 +142,72 @@ pub struct S3Config {
130142 pub metadata_endpoint : Option < String > ,
131143}
132144
145+ /// This represents the server side encryption to be
146+ /// used when working with S3 objects.
147+ #[ derive( Debug , Clone ) ]
148+ pub enum SSECEncryptionKey {
149+ /// https://docs.aws.amazon.com/AmazonS3/latest/userguide/ServerSideEncryptionCustomerKeys.html
150+ SseC {
151+ // algorithm unused but being tracked separately to maintain
152+ // consistent interface via CLI if AWS adds any new algorithms
153+ // in future.
154+ _algorithm : ObjectEncryptionAlgorithm ,
155+ base64_encryption_key : String ,
156+ } ,
157+ }
158+
159+ impl FromStr for SSECEncryptionKey {
160+ type Err = String ;
161+
162+ fn from_str ( s : & str ) -> Result < Self , Self :: Err > {
163+ let parts = s. split ( ':' ) . collect :: < Vec < _ > > ( ) ;
164+ if parts. len ( ) == 3 {
165+ let sse_type = parts[ 0 ] ;
166+ if sse_type != "SSE-C" {
167+ return Err ( "Only SSE-C is supported for object encryption for now" . into ( ) ) ;
168+ }
169+
170+ let algorithm = parts[ 1 ] ;
171+ let encryption_key = parts[ 2 ] ;
172+
173+ let alg = ObjectEncryptionAlgorithm :: from_str ( algorithm) ?;
174+
175+ Ok ( match alg {
176+ ObjectEncryptionAlgorithm :: Aes256 => SSECEncryptionKey :: SseC {
177+ _algorithm : alg,
178+ base64_encryption_key : encryption_key. to_owned ( ) ,
179+ } ,
180+ } )
181+ } else {
182+ Err ( "Expected SSE-C:AES256:<base64_encryption_key>" . into ( ) )
183+ }
184+ }
185+ }
186+
187+ #[ derive( Debug , Clone , Copy ) ]
188+ pub enum ObjectEncryptionAlgorithm {
189+ Aes256 ,
190+ }
191+
192+ impl FromStr for ObjectEncryptionAlgorithm {
193+ type Err = String ;
194+
195+ fn from_str ( s : & str ) -> Result < Self , Self :: Err > {
196+ match s {
197+ "AES256" => Ok ( ObjectEncryptionAlgorithm :: Aes256 ) ,
198+ _ => Err ( "Invalid SSE algorithm. Following are supported: AES256" . into ( ) ) ,
199+ }
200+ }
201+ }
202+
203+ impl Display for ObjectEncryptionAlgorithm {
204+ fn fmt ( & self , f : & mut std:: fmt:: Formatter < ' _ > ) -> std:: fmt:: Result {
205+ match self {
206+ ObjectEncryptionAlgorithm :: Aes256 => write ! ( f, "AES256" ) ,
207+ }
208+ }
209+ }
210+
133211impl S3Config {
134212 fn get_default_builder ( & self ) -> AmazonS3Builder {
135213 let mut client_options = ClientOptions :: default ( )
@@ -160,6 +238,17 @@ impl S3Config {
160238 . with_secret_access_key ( secret_key) ;
161239 }
162240
241+ if let Some ( ssec_encryption_key) = & self . ssec_encryption_key {
242+ match ssec_encryption_key {
243+ SSECEncryptionKey :: SseC {
244+ _algorithm,
245+ base64_encryption_key,
246+ } => {
247+ builder = builder. with_ssec_encryption ( base64_encryption_key) ;
248+ }
249+ }
250+ }
251+
163252 if let Ok ( relative_uri) = std:: env:: var ( AWS_CONTAINER_CREDENTIALS_RELATIVE_URI ) {
164253 builder = builder. with_config (
165254 AmazonS3ConfigKey :: ContainerCredentialsRelativeUri ,
0 commit comments