Skip to content

Commit

Permalink
authorization: implement new serviceAccounts field
Browse files Browse the repository at this point in the history
  • Loading branch information
howardjohn committed Dec 19, 2024
1 parent eae5084 commit a1f4b06
Show file tree
Hide file tree
Showing 4 changed files with 77 additions and 0 deletions.
2 changes: 2 additions & 0 deletions benches/throughput.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,8 @@ fn create_test_policies() -> Vec<Authorization> {
StringMatch::Exact("random-exac-2bc13".into()),
],
not_namespaces: vec![],
service_accounts: vec![],
not_service_accounts: vec![],
principals: vec![
StringMatch::Prefix("random-prefix-2b123".into()),
StringMatch::Suffix("random-postix-2b723".into()),
Expand Down
8 changes: 8 additions & 0 deletions proto/authorization.proto
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,9 @@ message Match {
repeated StringMatch namespaces = 1;
repeated StringMatch not_namespaces = 2;

repeated ServiceAccountMatch service_accounts = 11;
repeated ServiceAccountMatch not_service_accounts = 12;

repeated StringMatch principals = 3;
repeated StringMatch not_principals = 4;

Expand All @@ -75,6 +78,11 @@ message Address {
uint32 length = 2;
}

message ServiceAccountMatch {
string namespace = 1;
string serviceAccount = 2;
}

message StringMatch {
oneof match_type {
// exact string match
Expand Down
9 changes: 9 additions & 0 deletions src/admin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -458,6 +458,7 @@ mod tests {
use crate::xds::istio::security::Match as XdsMatch;
use crate::xds::istio::security::Rule as XdsRule;
use crate::xds::istio::security::StringMatch as XdsStringMatch;
use crate::xds::istio::security::ServiceAccountMatch as XdsServiceAccountMatch;
use crate::xds::istio::workload::gateway_address::Destination as XdsDestination;
use crate::xds::istio::workload::GatewayAddress as XdsGatewayAddress;
use crate::xds::istio::workload::LoadBalancing as XdsLoadBalancing;
Expand Down Expand Up @@ -714,6 +715,14 @@ mod tests {
not_namespaces: vec![XdsStringMatch {
match_type: Some(XdsMatchType::Exact("not-ns".to_string())),
}],
service_accounts: vec![XdsServiceAccountMatch {
namespace: "ns".into(),
service_account: "sa".into(),
}],
not_service_accounts: vec![XdsServiceAccountMatch {
namespace: "ns".into(),
service_account: "sa".into(),
}],
principals: vec![XdsStringMatch {
match_type: Some(XdsMatchType::Exact(
"spiffe://cluster.local/ns/ns/sa/sa".to_string(),
Expand Down
58 changes: 58 additions & 0 deletions src/rbac.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ use xds::istio::security::string_match::MatchType;
use xds::istio::security::Address as XdsAddress;
use xds::istio::security::Authorization as XdsRbac;
use xds::istio::security::Match;
use xds::istio::security::ServiceAccountMatch as XdsServiceAccountMatch;
use xds::istio::security::StringMatch as XdsStringMatch;

use crate::identity::Identity;
Expand Down Expand Up @@ -82,6 +83,7 @@ impl Authorization {

#[instrument(level = "trace", skip_all, fields(policy=self.to_key().as_str()))]
pub fn matches(&self, conn: &Connection) -> bool {
let full_identity = conn.src_identity.as_ref();
let id = conn
.src_identity
.as_ref()
Expand Down Expand Up @@ -133,6 +135,12 @@ impl Authorization {
&mg.not_destination_ports,
|p| *p == conn.dst.port(),
);
m &= Self::matches_internal(
"service_accounts",
&mg.service_accounts,
&mg.not_service_accounts,
|p| p.matches(&full_identity),
);
m &= Self::matches_internal(
"principals",
&mg.principals,
Expand Down Expand Up @@ -207,6 +215,10 @@ pub struct RbacMatch {
#[serde(skip_serializing_if = "Vec::is_empty", default)]
pub not_namespaces: Vec<StringMatch>,
#[serde(skip_serializing_if = "Vec::is_empty", default)]
pub service_accounts: Vec<ServiceAccountMatch>,
#[serde(skip_serializing_if = "Vec::is_empty", default)]
pub not_service_accounts: Vec<ServiceAccountMatch>,
#[serde(skip_serializing_if = "Vec::is_empty", default)]
pub principals: Vec<StringMatch>,
#[serde(skip_serializing_if = "Vec::is_empty", default)]
pub not_principals: Vec<StringMatch>,
Expand All @@ -228,6 +240,8 @@ impl RbacMatch {
fn is_empty(&self) -> bool {
self.namespaces.is_empty()
&& self.not_namespaces.is_empty()
&& self.service_accounts.is_empty()
&& self.not_service_accounts.is_empty()
&& self.principals.is_empty()
&& self.not_principals.is_empty()
&& self.source_ips.is_empty()
Expand Down Expand Up @@ -268,6 +282,26 @@ impl StringMatch {
}
}

#[derive(Debug, Hash, Eq, PartialEq, Clone, serde::Serialize, serde::Deserialize)]
pub struct ServiceAccountMatch {
namespace: Strng,
service_account: Strng,
}

impl ServiceAccountMatch {
pub fn matches(&self, check: &Option<&Identity>) -> bool {
match check {
Some(Identity::Spiffe {
trust_domain: _,
namespace,
service_account,
}) => namespace == &self.namespace && service_account == &self.service_account,
// No identity at all, this does not match
None => false,
}
}
}

#[derive(Debug, Hash, Eq, PartialEq, Clone, Copy, serde::Serialize, serde::Deserialize)]
pub enum RbacScope {
Global,
Expand Down Expand Up @@ -340,6 +374,12 @@ impl TryFrom<&Match> for RbacMatch {
.iter()
.filter_map(From::from)
.collect(),
service_accounts: resource.service_accounts.iter().map(From::from).collect(),
not_service_accounts: resource
.not_service_accounts
.iter()
.map(From::from)
.collect(),
principals: resource.principals.iter().filter_map(From::from).collect(),
not_principals: resource
.not_principals
Expand Down Expand Up @@ -401,6 +441,15 @@ impl From<&XdsStringMatch> for Option<StringMatch> {
}
}

impl From<&XdsServiceAccountMatch> for ServiceAccountMatch {
fn from(resource: &XdsServiceAccountMatch) -> Self {
Self {
namespace: resource.namespace.as_str().into(),
service_account: resource.service_account.as_str().into(),
}
}
}

#[cfg(test)]
mod tests {
use test_case::test_case;
Expand Down Expand Up @@ -620,6 +669,15 @@ mod tests {
&tls_conn() => false,
&tls_conn_alt() => true);

rbac_test!(service_accounts, vec![ServiceAccountMatch {namespace: "namespace".into(), service_account: "account".into() }],
&plaintext_conn() => false,
&tls_conn() => true,
&tls_conn_alt() => false);
rbac_test!(not_service_accounts, vec![ServiceAccountMatch {namespace: "namespace".into(), service_account: "account".into() }],
&plaintext_conn() => true,
&tls_conn() => false,
&tls_conn_alt() => true);

rbac_test!(principals, vec![StringMatch::Exact("td/ns/namespace/sa/account".into())],
&plaintext_conn() => false,
&tls_conn() => true,
Expand Down

0 comments on commit a1f4b06

Please sign in to comment.