Skip to content

Commit

Permalink
Use etcd encryption if enabled
Browse files Browse the repository at this point in the history
Signed-off-by: Michail Resvanis <[email protected]>
  • Loading branch information
mresvanis committed Oct 9, 2024
1 parent a3dd943 commit d6ae2c1
Show file tree
Hide file tree
Showing 6 changed files with 688 additions and 18 deletions.
53 changes: 50 additions & 3 deletions src/k8s_etcd.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use crate::cluster_crypto::locations::K8sResourceLocation;
use crate::encrypt::ResourceTransformers;
use crate::etcd_encoding;
use anyhow::{bail, ensure, Context, Result};
use etcd_client::{Client as EtcdClient, GetOptions};
Expand All @@ -24,16 +25,24 @@ pub(crate) struct InMemoryK8sEtcd {
etcd_keyvalue_hashmap: Mutex<HashMap<String, Vec<u8>>>,
edited: Mutex<HashMap<String, Vec<u8>>>,
deleted_keys: Mutex<HashSet<String>>,
decrypt_resource_transformers: Option<ResourceTransformers>,
encrypt_resource_transformers: Option<ResourceTransformers>,
}

impl InMemoryK8sEtcd {
/// Pass a None etcd_client to disable actual etcd access (dummy mode, empty key list).
pub(crate) fn new(etcd_client: Option<EtcdClient>) -> Self {
pub(crate) fn new(
etcd_client: Option<EtcdClient>,
decrypt_resource_transformers: Option<ResourceTransformers>,
encrypt_resource_transformers: Option<ResourceTransformers>,
) -> Self {
Self {
etcd_client: etcd_client.map(Arc::new),
etcd_keyvalue_hashmap: Mutex::new(HashMap::new()),
deleted_keys: Mutex::new(HashSet::new()),
edited: Mutex::new(HashMap::new()),
decrypt_resource_transformers,
encrypt_resource_transformers,
}
}

Expand Down Expand Up @@ -98,7 +107,21 @@ impl InMemoryK8sEtcd {
let key = key.clone();
let value = value.clone();
let etcd_client = Arc::clone(etcd_client);
let value = etcd_encoding::encode(value.as_slice()).await.context("encoding value")?;

let mut value = etcd_encoding::encode(value.as_slice()).await.context("encoding value")?;

if let Some(resource_transformers) = &self.encrypt_resource_transformers {
// https://github.com/kubernetes/apiserver/blob/master/pkg/storage/value/transformer.go#L172
if let Some(transformers) = resource_transformers
.resource_to_prefix_transformers
.get(&resource_from_key(key.to_string()))
{
value = transformers[0]
.encrypt(key.to_string(), value)
.await
.context("encrypting etcd value")?;
}
}

etcd_client
.kv_client()
Expand Down Expand Up @@ -134,7 +157,27 @@ impl InMemoryK8sEtcd {
if let Some(value) = get_result.kvs().first() {
let raw_etcd_value = value.value();

let decoded_value = etcd_encoding::decode(raw_etcd_value).await.context("decoding value")?;
let mut decoded_value = etcd_encoding::decode(raw_etcd_value).await.context("decoding value")?;

if let Some(resource_transformers) = &self.decrypt_resource_transformers {
// https://github.com/kubernetes/apiserver/blob/master/pkg/storage/value/transformer.go#L110
if let Some(transformers) = resource_transformers
.resource_to_prefix_transformers
.get(&resource_from_key(key.to_string()))
{
for transformer in transformers {
if raw_etcd_value.to_vec().starts_with(transformer.get_prefix().as_bytes()) {
let plaintext_value = transformer
.decrypt(key.to_string(), raw_etcd_value.to_vec())
.await
.context("decrypting etcd value")?;
decoded_value = etcd_encoding::decode(&plaintext_value).await.context("decoding value")?;
break;
}
}
}
}

self.etcd_keyvalue_hashmap
.lock()
.await
Expand Down Expand Up @@ -214,6 +257,10 @@ impl InMemoryK8sEtcd {
}
}

fn resource_from_key(key: String) -> String {
key.split('/').collect::<Vec<_>>()[2].to_string()
}

fn is_too_many_requests_error(delete_response: &std::prelude::v1::Result<etcd_client::DeleteResponse, etcd_client::Error>) -> bool {
match delete_response {
Ok(_) => false,
Expand Down
1 change: 1 addition & 0 deletions src/ocp_postprocess.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ pub(crate) mod additional_trust_bundle;
mod arguments;
pub(crate) mod chrony_config;
pub(crate) mod cluster_domain_rename;
pub(crate) mod encryption_config;
mod fnv;
mod go_base32;
pub(crate) mod hostname_rename;
Expand Down
71 changes: 71 additions & 0 deletions src/ocp_postprocess/encryption_config.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
use crate::config::EncryptionCustomizations;
use crate::{config::path::ConfigPath, k8s_etcd::InMemoryK8sEtcd};
use anyhow::{Context, Result};
use std::{path::Path, sync::Arc};

mod etcd_rename;
mod filesystem_rename;

pub(crate) async fn rename_all(
etcd_client: &Arc<InMemoryK8sEtcd>,
encryption_customizations: &EncryptionCustomizations,
dirs: &[ConfigPath],
files: &[ConfigPath],
) -> Result<()> {
fix_etcd_resources(etcd_client, encryption_customizations)
.await
.context("renaming etcd resources")?;

fix_filesystem_resources(encryption_customizations, dirs, files)
.await
.context("renaming filesystem resources")?;

Ok(())
}

async fn fix_filesystem_resources(
encryption_customizations: &EncryptionCustomizations,
dirs: &[ConfigPath],
files: &[ConfigPath],
) -> Result<()> {
for dir in dirs {
fix_dir_resources(encryption_customizations, dir).await?;
}

for file in files {
fix_file_resources(encryption_customizations, file).await?;
}

Ok(())
}

async fn fix_dir_resources(encryption_customizations: &EncryptionCustomizations, dir: &Path) -> Result<()> {
filesystem_rename::fix_filesystem_kas_pods(encryption_customizations, dir)
.await
.context(format!("fix filesystem kube-apiserver encryption-config in {:?}", dir))?;
Ok(())
}

async fn fix_file_resources(_encryption_customizations: &EncryptionCustomizations, _file: &Path) -> Result<()> {
Ok(())
}

async fn fix_etcd_resources(etcd_client: &Arc<InMemoryK8sEtcd>, encryption_customizations: &EncryptionCustomizations) -> Result<()> {
etcd_rename::update_kube_apiserver_encryption_config(etcd_client, encryption_customizations)
.await
.context("updating kube-apiserver encryption-config")?;

etcd_rename::update_openshift_apiserver_encryption_config(etcd_client, encryption_customizations)
.await
.context("updating openshift-apiserver encryption-config")?;

etcd_rename::update_oauth_apiserver_encryption_config(etcd_client, encryption_customizations)
.await
.context("updating oauth-apiserver encryption-config")?;

etcd_rename::reencrypt_resources(etcd_client)
.await
.context("re-encrypting etcd resources")?;

Ok(())
}
Loading

0 comments on commit d6ae2c1

Please sign in to comment.