Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CDH | Refactor secure mount module #539

Merged
merged 5 commits into from
Apr 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion confidential-data-hub/docs/SECURE_STORAGE.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ We reuse [direct block device assigned volume feature](https://github.com/kata-c

[Aliyun OSS](https://www.alibabacloud.com/product/object-storage-service) is an object storage service provided by Alibaba Cloud (Aliyun).

The [plugin](../storage/src/volume_type/alibaba_cloud_oss/) provides two different modes for secure mount.
The [plugin](../storage/src/volume_type/aliyun) provides two different modes for secure mount.

Confidential Data Hub's `secure_mount()` [API](../hub/protos/api.proto) will help to instrument this.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,39 +66,39 @@ Run CDH
confidential-data-hub
```

Prepare a request JSON `storage.json`
Prepare a request JSON `storage.json`. This example is for aliyun OSS.
```json
{
"driver": "",
"driver_options": [
"alibaba-cloud-oss={\"akId\":\"XXX\",\"akSecret\":\"XXX\",\"annotations\":\"\",\"bucket\":\"<bucket-id>\",\"encrypted\":\"gocryptfs\",\"encPasswd\":\"<PASSWORD>\",\"kmsKeyId\":\"\",\"otherOpts\":\"-o max_stat_cache_size=0 -o allow_other\",\"path\":\"<bucket-path>\",\"readonly\":\"\",\"targetPath\":\"/mnt/aliyun-oss\",\"url\":\"https://oss-cn-beijing.aliyuncs.com\",\"volumeId\":\"\"}"
],
"source": "",
"fstype": "",
"options": [],
"volume_type": "alibaba-cloud-oss",
"options": {
"akId": "XXX",
"akSecret": "XXX",
"annotations": "",
"bucket": "<bucket-id>",
"encrypted": "gocryptfs",
"encPasswd": "<PASSWORD>",
"kmsKeyId": "",
"otherOpts": "-o max_stat_cache_size=0 -o allow_other",
"path": "<bucket-path>",
"readonly": "",
"targetPath": "/mnt/aliyun-oss",
"url": "https://oss-cn-beijing.aliyuncs.com",
"volumeId": ""
},
"flags": [],
"mount_point": "/mnt/target-path"
}
Comment on lines 71 to 90
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I hope that this new request format makes much more sense to you. : ) @bpradipt @fitzthum

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Xynnn007 indeed :-)
A related question, can I use the secure mount functionality today to mount S3 or Azure blob volumes inside the container today ? Or code changes will be needed to support different object storages ?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Take aliyun oss for example, we might need

  1. CDH to impl the plugin. If 1 is achieved, a confidential VM support is ok. The following points are for confidential containers.
  2. kata-runtime & kata-agent deliver secure-mount metadata to CDH. This is what https://github.com/kata-containers/kata-containers/pull/7965/files did.
  3. The CSI driver of S3/Azure blob/other kinds of storages should support deliver mount info to kata as aliyun-oss does

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @Xynnn007. This makes sense

```
- `mount_point`: the target path to mount the decrypted storage.

The only string member of `driver_options` looks like `alibaba-cloud-oss=XXX`. `XXX` here is an escaped JSON object.
```json
{
"akId": "XXX",
"akSecret": "XXX",
"annotations": "",
"bucket": "<bucket-id>",
"encrypted": "gocryptfs",
"encPasswd": "<PASSWORD>",
"kmsKeyId": "",
"otherOpts": "-o max_stat_cache_size=0 -o allow_other",
"path": "/<bucket-path>",
"readonly": "",
"targetPath": "/mnt/aliyun-oss",
"url": "https://oss-cn-beijing.aliyuncs.com",
"volumeId": ""
}
```
Fields:
- `volume_type`: the secure mount plugin type name. It will determine how the rest of the fields are used.
- `options`: a key-value map that specifies the settings for the mount operation. Different plugin can define
different keys of the `option`. In this example all keys are for Aliyun OSS.
- `flags`: a string list that specifies the settings for the mount operation. Different plugin can define different
usage of this field.
- `mount_point`: The target mount path of the operation.

Let's dive into the example's `options` field. Note that this example is for Aliyun OSS and different mount plugin
can define its own `options`!

The fields here
- `akId`: is Id of AK to access the OSS bucket. This will be provided when creating the OSS bucket. This can also be a [sealed secret](../SEALED_SECRET.md).
Expand Down
10 changes: 4 additions & 6 deletions confidential-data-hub/hub/protos/api.proto
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,10 @@ message GetResourceResponse {
}

message SecureMountRequest {
string driver = 1;
repeated string driver_options = 2;
string source = 3;
string fstype = 4;
repeated string options = 5;
string mount_point = 6;
string volume_type = 1;
map<string, string> options = 2;
repeated string flags = 3;
string mount_point = 4;
}

message SecureMountResponse {
Expand Down
6 changes: 2 additions & 4 deletions confidential-data-hub/hub/src/bin/cdh-tool.rs
Original file line number Diff line number Diff line change
Expand Up @@ -142,10 +142,8 @@ async fn main() {
let storage: Storage =
serde_json::from_slice(&storage_manifest).expect("deserialize Storage");
let req = SecureMountRequest {
driver: storage.driver,
driver_options: storage.driver_options,
source: storage.source,
fstype: storage.fstype,
volume_type: storage.volume_type,
flags: storage.flags,
options: storage.options,
mount_point: storage.mount_point,
..Default::default()
Expand Down
156 changes: 68 additions & 88 deletions confidential-data-hub/hub/src/bin/protos/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -517,16 +517,12 @@ impl ::protobuf::reflect::ProtobufValue for GetResourceResponse {
#[derive(PartialEq,Clone,Default,Debug)]
pub struct SecureMountRequest {
// message fields
// @@protoc_insertion_point(field:api.SecureMountRequest.driver)
pub driver: ::std::string::String,
// @@protoc_insertion_point(field:api.SecureMountRequest.driver_options)
pub driver_options: ::std::vec::Vec<::std::string::String>,
// @@protoc_insertion_point(field:api.SecureMountRequest.source)
pub source: ::std::string::String,
// @@protoc_insertion_point(field:api.SecureMountRequest.fstype)
pub fstype: ::std::string::String,
// @@protoc_insertion_point(field:api.SecureMountRequest.volume_type)
pub volume_type: ::std::string::String,
// @@protoc_insertion_point(field:api.SecureMountRequest.options)
pub options: ::std::vec::Vec<::std::string::String>,
pub options: ::std::collections::HashMap<::std::string::String, ::std::string::String>,
// @@protoc_insertion_point(field:api.SecureMountRequest.flags)
pub flags: ::std::vec::Vec<::std::string::String>,
// @@protoc_insertion_point(field:api.SecureMountRequest.mount_point)
pub mount_point: ::std::string::String,
// special fields
Expand All @@ -546,33 +542,23 @@ impl SecureMountRequest {
}

fn generated_message_descriptor_data() -> ::protobuf::reflect::GeneratedMessageDescriptorData {
let mut fields = ::std::vec::Vec::with_capacity(6);
let mut fields = ::std::vec::Vec::with_capacity(4);
let mut oneofs = ::std::vec::Vec::with_capacity(0);
fields.push(::protobuf::reflect::rt::v2::make_simpler_field_accessor::<_, _>(
"driver",
|m: &SecureMountRequest| { &m.driver },
|m: &mut SecureMountRequest| { &mut m.driver },
"volume_type",
|m: &SecureMountRequest| { &m.volume_type },
|m: &mut SecureMountRequest| { &mut m.volume_type },
));
fields.push(::protobuf::reflect::rt::v2::make_vec_simpler_accessor::<_, _>(
"driver_options",
|m: &SecureMountRequest| { &m.driver_options },
|m: &mut SecureMountRequest| { &mut m.driver_options },
));
fields.push(::protobuf::reflect::rt::v2::make_simpler_field_accessor::<_, _>(
"source",
|m: &SecureMountRequest| { &m.source },
|m: &mut SecureMountRequest| { &mut m.source },
));
fields.push(::protobuf::reflect::rt::v2::make_simpler_field_accessor::<_, _>(
"fstype",
|m: &SecureMountRequest| { &m.fstype },
|m: &mut SecureMountRequest| { &mut m.fstype },
));
fields.push(::protobuf::reflect::rt::v2::make_vec_simpler_accessor::<_, _>(
fields.push(::protobuf::reflect::rt::v2::make_map_simpler_accessor::<_, _, _>(
"options",
|m: &SecureMountRequest| { &m.options },
|m: &mut SecureMountRequest| { &mut m.options },
));
fields.push(::protobuf::reflect::rt::v2::make_vec_simpler_accessor::<_, _>(
"flags",
|m: &SecureMountRequest| { &m.flags },
|m: &mut SecureMountRequest| { &mut m.flags },
));
fields.push(::protobuf::reflect::rt::v2::make_simpler_field_accessor::<_, _>(
"mount_point",
|m: &SecureMountRequest| { &m.mount_point },
Expand All @@ -597,21 +583,27 @@ impl ::protobuf::Message for SecureMountRequest {
while let Some(tag) = is.read_raw_tag_or_eof()? {
match tag {
10 => {
self.driver = is.read_string()?;
self.volume_type = is.read_string()?;
},
18 => {
self.driver_options.push(is.read_string()?);
let len = is.read_raw_varint32()?;
let old_limit = is.push_limit(len as u64)?;
let mut key = ::std::default::Default::default();
let mut value = ::std::default::Default::default();
while let Some(tag) = is.read_raw_tag_or_eof()? {
match tag {
10 => key = is.read_string()?,
18 => value = is.read_string()?,
_ => ::protobuf::rt::skip_field_for_tag(tag, is)?,
};
}
is.pop_limit(old_limit);
self.options.insert(key, value);
},
26 => {
self.source = is.read_string()?;
self.flags.push(is.read_string()?);
},
34 => {
self.fstype = is.read_string()?;
},
42 => {
self.options.push(is.read_string()?);
},
50 => {
self.mount_point = is.read_string()?;
},
tag => {
Expand All @@ -626,47 +618,44 @@ impl ::protobuf::Message for SecureMountRequest {
#[allow(unused_variables)]
fn compute_size(&self) -> u64 {
let mut my_size = 0;
if !self.driver.is_empty() {
my_size += ::protobuf::rt::string_size(1, &self.driver);
if !self.volume_type.is_empty() {
my_size += ::protobuf::rt::string_size(1, &self.volume_type);
}
for value in &self.driver_options {
my_size += ::protobuf::rt::string_size(2, &value);
for (k, v) in &self.options {
let mut entry_size = 0;
entry_size += ::protobuf::rt::string_size(1, &k);
entry_size += ::protobuf::rt::string_size(2, &v);
my_size += 1 + ::protobuf::rt::compute_raw_varint64_size(entry_size) + entry_size
};
if !self.source.is_empty() {
my_size += ::protobuf::rt::string_size(3, &self.source);
}
if !self.fstype.is_empty() {
my_size += ::protobuf::rt::string_size(4, &self.fstype);
}
for value in &self.options {
my_size += ::protobuf::rt::string_size(5, &value);
for value in &self.flags {
my_size += ::protobuf::rt::string_size(3, &value);
};
if !self.mount_point.is_empty() {
my_size += ::protobuf::rt::string_size(6, &self.mount_point);
my_size += ::protobuf::rt::string_size(4, &self.mount_point);
}
my_size += ::protobuf::rt::unknown_fields_size(self.special_fields.unknown_fields());
self.special_fields.cached_size().set(my_size as u32);
my_size
}

fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::Result<()> {
if !self.driver.is_empty() {
os.write_string(1, &self.driver)?;
if !self.volume_type.is_empty() {
os.write_string(1, &self.volume_type)?;
}
for v in &self.driver_options {
for (k, v) in &self.options {
let mut entry_size = 0;
entry_size += ::protobuf::rt::string_size(1, &k);
entry_size += ::protobuf::rt::string_size(2, &v);
os.write_raw_varint32(18)?; // Tag.
os.write_raw_varint32(entry_size as u32)?;
os.write_string(1, &k)?;
os.write_string(2, &v)?;
};
if !self.source.is_empty() {
os.write_string(3, &self.source)?;
}
if !self.fstype.is_empty() {
os.write_string(4, &self.fstype)?;
}
for v in &self.options {
os.write_string(5, &v)?;
for v in &self.flags {
os.write_string(3, &v)?;
};
if !self.mount_point.is_empty() {
os.write_string(6, &self.mount_point)?;
os.write_string(4, &self.mount_point)?;
}
os.write_unknown_fields(self.special_fields.unknown_fields())?;
::std::result::Result::Ok(())
Expand All @@ -685,26 +674,16 @@ impl ::protobuf::Message for SecureMountRequest {
}

fn clear(&mut self) {
self.driver.clear();
self.driver_options.clear();
self.source.clear();
self.fstype.clear();
self.volume_type.clear();
self.options.clear();
self.flags.clear();
self.mount_point.clear();
self.special_fields.clear();
}

fn default_instance() -> &'static SecureMountRequest {
static instance: SecureMountRequest = SecureMountRequest {
driver: ::std::string::String::new(),
driver_options: ::std::vec::Vec::new(),
source: ::std::string::String::new(),
fstype: ::std::string::String::new(),
options: ::std::vec::Vec::new(),
mount_point: ::std::string::String::new(),
special_fields: ::protobuf::SpecialFields::new(),
};
&instance
static instance: ::protobuf::rt::Lazy<SecureMountRequest> = ::protobuf::rt::Lazy::new();
instance.get(SecureMountRequest::new)
}
}

Expand Down Expand Up @@ -853,17 +832,18 @@ static file_descriptor_proto_data: &'static [u8] = b"\
laintext\x18\x01\x20\x01(\x0cR\tplaintext\"8\n\x12GetResourceRequest\x12\
\"\n\x0cResourcePath\x18\x01\x20\x01(\tR\x0cResourcePath\"1\n\x13GetReso\
urceResponse\x12\x1a\n\x08Resource\x18\x01\x20\x01(\x0cR\x08Resource\"\
\xbe\x01\n\x12SecureMountRequest\x12\x16\n\x06driver\x18\x01\x20\x01(\tR\
\x06driver\x12%\n\x0edriver_options\x18\x02\x20\x03(\tR\rdriverOptions\
\x12\x16\n\x06source\x18\x03\x20\x01(\tR\x06source\x12\x16\n\x06fstype\
\x18\x04\x20\x01(\tR\x06fstype\x12\x18\n\x07options\x18\x05\x20\x03(\tR\
\x07options\x12\x1f\n\x0bmount_point\x18\x06\x20\x01(\tR\nmountPoint\"4\
\n\x13SecureMountResponse\x12\x1d\n\nmount_path\x18\x01\x20\x01(\tR\tmou\
ntPath2V\n\x13SealedSecretService\x12?\n\x0cUnsealSecret\x12\x16.api.Uns\
ealSecretInput\x1a\x17.api.UnsealSecretOutput2V\n\x12GetResourceService\
\x12@\n\x0bGetResource\x12\x17.api.GetResourceRequest\x1a\x18.api.GetRes\
ourceResponse2V\n\x12SecureMountService\x12@\n\x0bSecureMount\x12\x17.ap\
i.SecureMountRequest\x1a\x18.api.SecureMountResponseb\x06proto3\
\xe8\x01\n\x12SecureMountRequest\x12\x1f\n\x0bvolume_type\x18\x01\x20\
\x01(\tR\nvolumeType\x12>\n\x07options\x18\x02\x20\x03(\x0b2$.api.Secure\
MountRequest.OptionsEntryR\x07options\x12\x14\n\x05flags\x18\x03\x20\x03\
(\tR\x05flags\x12\x1f\n\x0bmount_point\x18\x04\x20\x01(\tR\nmountPoint\
\x1a:\n\x0cOptionsEntry\x12\x10\n\x03key\x18\x01\x20\x01(\tR\x03key\x12\
\x14\n\x05value\x18\x02\x20\x01(\tR\x05value:\x028\x01\"4\n\x13SecureMou\
ntResponse\x12\x1d\n\nmount_path\x18\x01\x20\x01(\tR\tmountPath2V\n\x13S\
ealedSecretService\x12?\n\x0cUnsealSecret\x12\x16.api.UnsealSecretInput\
\x1a\x17.api.UnsealSecretOutput2V\n\x12GetResourceService\x12@\n\x0bGetR\
esource\x12\x17.api.GetResourceRequest\x1a\x18.api.GetResourceResponse2V\
\n\x12SecureMountService\x12@\n\x0bSecureMount\x12\x17.api.SecureMountRe\
quest\x1a\x18.api.SecureMountResponseb\x06proto3\
";

/// `FileDescriptorProto` object which was a source for this generated file
Expand Down
6 changes: 2 additions & 4 deletions confidential-data-hub/hub/src/bin/server/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -166,11 +166,9 @@ impl SecureMountService for Server {
let reader = HUB.read().await;
let reader = reader.as_ref().expect("must be initialized");
let storage = Storage {
driver: req.driver,
driver_options: req.driver_options,
source: req.source,
fstype: req.fstype,
volume_type: req.volume_type,
options: req.options,
flags: req.flags,
mount_point: req.mount_point,
};
let resource = reader.secure_mount(storage).await.map_err(|e| {
Expand Down
2 changes: 2 additions & 0 deletions confidential-data-hub/storage/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,13 @@ edition = "2021"

[dependencies]
anyhow.workspace = true
async-trait.workspace = true
base64.workspace = true
log.workspace = true
secret = { path = "../secret" }
serde.workspace = true
serde_json.workspace = true
strum = { workspace = true, features = ["derive"] }
tempfile = { workspace = true, optional = true }
thiserror.workspace = true
tokio = { workspace = true, optional = true }
Expand Down
Loading
Loading