-
Notifications
You must be signed in to change notification settings - Fork 283
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Provide interface to allow customization of SPIFFE URI format
Signed-off-by: Henry Avetisyan <[email protected]>
- Loading branch information
1 parent
baf7c7c
commit 2e1ca9b
Showing
19 changed files
with
641 additions
and
160 deletions.
There are no files selected for viewing
89 changes: 89 additions & 0 deletions
89
...a/server_common/src/main/java/com/yahoo/athenz/common/server/spiffe/SpiffeUriManager.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
/* | ||
* | ||
* * Copyright The Athenz Authors | ||
* * | ||
* * Licensed under the Apache License, Version 2.0 (the "License"); | ||
* * you may not use this file except in compliance with the License. | ||
* * You may obtain a copy of the License at | ||
* * | ||
* * http://www.apache.org/licenses/LICENSE-2.0 | ||
* * | ||
* * Unless required by applicable law or agreed to in writing, software | ||
* * distributed under the License is distributed on an "AS IS" BASIS, | ||
* * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* * See the License for the specific language governing permissions and | ||
* * limitations under the License. | ||
* | ||
*/ | ||
|
||
package com.yahoo.athenz.common.server.spiffe; | ||
|
||
import org.slf4j.Logger; | ||
import org.slf4j.LoggerFactory; | ||
|
||
import java.util.ArrayList; | ||
import java.util.List; | ||
|
||
public class SpiffeUriManager { | ||
|
||
private static final Logger LOGGER = LoggerFactory.getLogger(SpiffeUriManager.class); | ||
|
||
public static final String ZTS_PROP_SPIFFE_URI_VALIDATOR_CLASSES = "athenz.zts.spiffe_uri_validator_classes"; | ||
public static final String ZTS_DEFAULT_SPIFFE_URI_VALIDATOR_CLASSES = "com.yahoo.athenz.common.server.spiffe.impl.SpiffeUriTrustDomain,com.yahoo.athenz.common.server.spiffe.impl.SpiffeUriBasic"; | ||
|
||
private final List<SpiffeUriValidator> validators; | ||
|
||
public SpiffeUriManager() { | ||
|
||
final String validatorClasses = System.getProperty(ZTS_PROP_SPIFFE_URI_VALIDATOR_CLASSES, | ||
ZTS_DEFAULT_SPIFFE_URI_VALIDATOR_CLASSES); | ||
|
||
validators = new ArrayList<>(); | ||
String[] validatorClassList = validatorClasses.split(","); | ||
for (String validatorClass : validatorClassList) { | ||
SpiffeUriValidator validator = getValidator(validatorClass.trim()); | ||
if (validator == null) { | ||
throw new IllegalArgumentException("Invalid spiffe uri validator: " + validatorClass); | ||
} | ||
validators.add(validator); | ||
} | ||
} | ||
|
||
SpiffeUriValidator getValidator(String className) { | ||
|
||
LOGGER.debug("Loading spiffe uri validator {}...", className); | ||
|
||
SpiffeUriValidator validator; | ||
try { | ||
validator = (SpiffeUriValidator) Class.forName(className).getDeclaredConstructor().newInstance(); | ||
} catch (Exception ex) { | ||
LOGGER.error("Invalid validator class: {}", className, ex); | ||
return null; | ||
} | ||
return validator; | ||
} | ||
|
||
public boolean validateServiceCertUri(final String spiffeUri, final String domainName, final String serviceName, | ||
final String namespace) { | ||
|
||
for (SpiffeUriValidator validator : validators) { | ||
if (validator.validateServiceCertUri(spiffeUri, domainName, serviceName, namespace)) { | ||
return true; | ||
} | ||
} | ||
LOGGER.error("unable to validate service spiffe uri: {}, domainName: {}, serviceName: {}, namespace: {}", | ||
spiffeUri, domainName, serviceName, namespace); | ||
return false; | ||
} | ||
|
||
public boolean validateRoleCertUri(final String spiffeUri, final String domainName, final String roleName) { | ||
for (SpiffeUriValidator validator : validators) { | ||
if (validator.validateRoleCertUri(spiffeUri, domainName, roleName)) { | ||
return true; | ||
} | ||
} | ||
LOGGER.error("unable to validate role spiffe uri: {}, domainName: {}, roleName: {}", | ||
spiffeUri, domainName, roleName); | ||
return false; | ||
} | ||
} |
45 changes: 45 additions & 0 deletions
45
...server_common/src/main/java/com/yahoo/athenz/common/server/spiffe/SpiffeUriValidator.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
/* | ||
* | ||
* * Copyright The Athenz Authors | ||
* * | ||
* * Licensed under the Apache License, Version 2.0 (the "License"); | ||
* * you may not use this file except in compliance with the License. | ||
* * You may obtain a copy of the License at | ||
* * | ||
* * http://www.apache.org/licenses/LICENSE-2.0 | ||
* * | ||
* * Unless required by applicable law or agreed to in writing, software | ||
* * distributed under the License is distributed on an "AS IS" BASIS, | ||
* * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* * See the License for the specific language governing permissions and | ||
* * limitations under the License. | ||
* | ||
*/ | ||
|
||
package com.yahoo.athenz.common.server.spiffe; | ||
|
||
/** | ||
* An interface that allows system administrators to validate SPIFFE URIs | ||
* based on their own requirements. | ||
*/ | ||
public interface SpiffeUriValidator { | ||
|
||
/** | ||
* Validate the SPIFFE URI for service identity certificates based on the system requirements. | ||
* @param spiffeUri the SPIFFE URI to be validated (e.g. spiffe://athenz.domain/sa/service) | ||
* @param domainName the domain name of the service | ||
* @param serviceName the service name | ||
* @param namespace the namespace of the service (typically a Kubernetes namespace) | ||
* @return true if the SPIFFE URI is valid, false otherwise | ||
*/ | ||
boolean validateServiceCertUri(final String spiffeUri, final String domainName, final String serviceName, final String namespace); | ||
|
||
/** | ||
* Validate the SPIFFE URI for rike certificates based on the system requirements. | ||
* @param spiffeUri the SPIFFE URI to be validated (e.g. spiffe://athenz.domain/ra/writers) | ||
* @param domainName the domain name of the service | ||
* @param roleName the role name | ||
* @return true if the SPIFFE URI is valid, false otherwise | ||
*/ | ||
boolean validateRoleCertUri(final String spiffeUri, final String domainName, final String roleName); | ||
} |
52 changes: 52 additions & 0 deletions
52
...erver_common/src/main/java/com/yahoo/athenz/common/server/spiffe/impl/SpiffeUriBasic.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
/* | ||
* | ||
* * Copyright The Athenz Authors | ||
* * | ||
* * Licensed under the Apache License, Version 2.0 (the "License"); | ||
* * you may not use this file except in compliance with the License. | ||
* * You may obtain a copy of the License at | ||
* * | ||
* * http://www.apache.org/licenses/LICENSE-2.0 | ||
* * | ||
* * Unless required by applicable law or agreed to in writing, software | ||
* * distributed under the License is distributed on an "AS IS" BASIS, | ||
* * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* * See the License for the specific language governing permissions and | ||
* * limitations under the License. | ||
* | ||
*/ | ||
|
||
package com.yahoo.athenz.common.server.spiffe.impl; | ||
|
||
import com.yahoo.athenz.common.server.spiffe.SpiffeUriValidator; | ||
|
||
/** | ||
* Basic implementation of SpiffeUriValidator interface. This class validates the SPIFFE URI | ||
* with the following formats: | ||
* Service Cert URI: spiffe://<domainName>/sa/<serviceName> | ||
* Example: spiffe://athenz/sa/api | ||
* Role Cert URI: spiffe://<domainName>/ra/<roleName> | ||
* Example: spiffe://athenz/ra/readers | ||
*/ | ||
public class SpiffeUriBasic implements SpiffeUriValidator { | ||
|
||
/** | ||
* Supported Service Cert URI: spiffe://<domainName>/sa/<serviceName> | ||
* Example: spiffe://athenz/sa/api | ||
*/ | ||
@Override | ||
public boolean validateServiceCertUri(String spiffeUri, String domainName, String serviceName, String namespace) { | ||
final String reqUri = String.format("spiffe://%s/sa/%s", domainName, serviceName); | ||
return reqUri.equalsIgnoreCase(spiffeUri); | ||
} | ||
|
||
/** | ||
* Supported Role Cert URI: spiffe://<domainName>/ra/<roleName> | ||
* Example: spiffe://athenz/ra/readers | ||
*/ | ||
@Override | ||
public boolean validateRoleCertUri(String spiffeUri, String domainName, String roleName) { | ||
final String reqUri = String.format("spiffe://%s/ra/%s", domainName, roleName); | ||
return reqUri.equalsIgnoreCase(spiffeUri); | ||
} | ||
} |
61 changes: 61 additions & 0 deletions
61
...common/src/main/java/com/yahoo/athenz/common/server/spiffe/impl/SpiffeUriTrustDomain.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
/* | ||
* | ||
* * Copyright The Athenz Authors | ||
* * | ||
* * Licensed under the Apache License, Version 2.0 (the "License"); | ||
* * you may not use this file except in compliance with the License. | ||
* * You may obtain a copy of the License at | ||
* * | ||
* * http://www.apache.org/licenses/LICENSE-2.0 | ||
* * | ||
* * Unless required by applicable law or agreed to in writing, software | ||
* * distributed under the License is distributed on an "AS IS" BASIS, | ||
* * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* * See the License for the specific language governing permissions and | ||
* * limitations under the License. | ||
* | ||
*/ | ||
|
||
package com.yahoo.athenz.common.server.spiffe.impl; | ||
|
||
import com.yahoo.athenz.common.server.spiffe.SpiffeUriValidator; | ||
import org.eclipse.jetty.util.StringUtil; | ||
|
||
/** | ||
* Trust Domain implementation of SpiffeUriValidator interface. This class validates the SPIFFE URI | ||
* with the following formats: | ||
* Service Cert URI: spiffe://<trustDomain>/ns/<namespace>/sa/<domainName>.<serviceName> | ||
* Example: spiffe://athenz.io/ns/prod/sa/athenz.api | ||
* Role Cert URI: spiffe://<trustDomain>/ns/<domainName>/ra/<roleName> | ||
* Example: spiffe://athenz.io/ns/athenz/ra/readers | ||
*/ | ||
public class SpiffeUriTrustDomain implements SpiffeUriValidator { | ||
|
||
private static final String SPIFFE_DEFAULT_NAMESPACE = "default"; | ||
|
||
private static final String SPIFFE_PROP_TRUST_DOMAIN = "athenz.zts.spiffe_trust_domain"; | ||
private static final String SPIFFE_TRUST_DOMAIN = System.getProperty(SPIFFE_PROP_TRUST_DOMAIN, "athenz.io"); | ||
|
||
/** | ||
* Service Cert URI: spiffe://<trustDomain>/ns/<namespace>/sa/<domainName>.<serviceName> | ||
* Example: spiffe://athenz.io/ns/prod/sa/athenz.api | ||
*/ | ||
@Override | ||
public boolean validateServiceCertUri(String spiffeUri, String domainName, String serviceName, String namespace) { | ||
final String ns = StringUtil.isEmpty(namespace) ? SPIFFE_DEFAULT_NAMESPACE : namespace; | ||
final String reqUri = String.format("spiffe://%s/ns/%s/sa/%s.%s", SPIFFE_TRUST_DOMAIN, | ||
ns, domainName, serviceName); | ||
return reqUri.equalsIgnoreCase(spiffeUri); | ||
} | ||
|
||
/** | ||
* Role Cert URI: spiffe://<trustDomain>/ns/<domainName>/ra/<roleName> | ||
* Example: spiffe://athenz.io/ns/athenz/ra/readers | ||
*/ | ||
@Override | ||
public boolean validateRoleCertUri(String spiffeUri, String domainName, String roleName) { | ||
final String reqUri = String.format("spiffe://%s/ns/%s/ra/%s", SPIFFE_TRUST_DOMAIN, | ||
domainName, roleName); | ||
return reqUri.equalsIgnoreCase(spiffeUri); | ||
} | ||
} |
87 changes: 87 additions & 0 deletions
87
...rver_common/src/test/java/com/yahoo/athenz/common/server/spiffe/SpiffeUriManagerTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
/* | ||
* Copyright The Athenz Authors | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
package com.yahoo.athenz.common.server.spiffe; | ||
|
||
import com.yahoo.athenz.common.server.spiffe.impl.SpiffeUriTrustDomain; | ||
import org.testng.annotations.BeforeClass; | ||
import org.testng.annotations.Test; | ||
|
||
import static org.testng.Assert.*; | ||
|
||
public class SpiffeUriManagerTest { | ||
|
||
@BeforeClass | ||
public void setup() { | ||
System.setProperty("athenz.zts.spiffe_trust_domain", "spiffe.athenz.io"); | ||
} | ||
|
||
@Test | ||
public void testValidateServiceCertUriDefaultClasses() { | ||
|
||
System.clearProperty("athenz.zts.spiffe_uri_validator_classes"); | ||
SpiffeUriManager manager = new SpiffeUriManager(); | ||
|
||
assertTrue(manager.validateServiceCertUri("spiffe://athenz/sa/api", "athenz", "api", null)); | ||
assertTrue(manager.validateServiceCertUri("spiffe://athenz/sa/api", "athenz", "api", "default")); | ||
|
||
assertFalse(manager.validateServiceCertUri("spiffe://athenz/sa/api", "athenz.prod", "api", "default")); | ||
assertFalse(manager.validateServiceCertUri("spiffe://athenz/sa/api", "athenz", "backend", "default")); | ||
|
||
assertTrue(manager.validateServiceCertUri("spiffe://spiffe.athenz.io/ns/default/sa/athenz.api", "athenz", "api", null)); | ||
assertTrue(manager.validateServiceCertUri("spiffe://spiffe.athenz.io/ns/default/sa/athenz.api", "athenz", "api", "default")); | ||
assertTrue(manager.validateServiceCertUri("spiffe://spiffe.athenz.io/ns/prod/sa/athenz.api", "athenz", "api", "prod")); | ||
|
||
assertFalse(manager.validateServiceCertUri("spiffe://spiffe.athenz.io/ns/default/sa/athenz.api", "athenz", "api", "prod")); | ||
assertFalse(manager.validateServiceCertUri("spiffe://spiffe.athenz.io/ns/default/sa/athenz.backend", "athenz", "api", "default")); | ||
assertFalse(manager.validateServiceCertUri("spiffe://spiffe.athenz.io/ns/prod/sa/athenz.api", "athenz.prod", "api", "prod")); | ||
|
||
assertFalse(manager.validateServiceCertUri("spiffe://athenz.io/ns/prod/sa/athenz.api", "athenz", "api", "prod")); | ||
} | ||
|
||
@Test | ||
public void testValidateRoleCertUriDefaultClasses() { | ||
|
||
System.clearProperty("athenz.zts.spiffe_uri_validator_classes"); | ||
SpiffeUriManager manager = new SpiffeUriManager(); | ||
|
||
assertTrue(manager.validateRoleCertUri("spiffe://athenz/ra/readers", "athenz", "readers")); | ||
assertTrue(manager.validateRoleCertUri("spiffe://athenz/ra/writers", "athenz", "writers")); | ||
|
||
assertFalse(manager.validateRoleCertUri("spiffe://athenz/ra/readers", "athenz.prod", "readers")); | ||
assertFalse(manager.validateRoleCertUri("spiffe://athenz/ra/readers", "athenz", "writers")); | ||
|
||
assertTrue(manager.validateRoleCertUri("spiffe://spiffe.athenz.io/ns/athenz/ra/readers", "athenz", "readers")); | ||
|
||
assertFalse(manager.validateRoleCertUri("spiffe://spiffe.athenz.io/ns/athenz/ra/readers", "athenz", "writers")); | ||
assertFalse(manager.validateRoleCertUri("spiffe://spiffe.athenz.io/ns/athenz/ra/readers", "athenz.prod", "readers")); | ||
|
||
assertFalse(manager.validateRoleCertUri("spiffe://athenz.io/ns/athenz/ra/readers", "athenz", "readers")); | ||
} | ||
|
||
@Test | ||
public void testValidateInvalidClass() { | ||
|
||
System.setProperty("athenz.zts.spiffe_uri_validator_classes", "com.yahoo.athenz.common.server.spiffe.impl.InvalidClass"); | ||
try { | ||
new SpiffeUriManager(); | ||
fail(); | ||
} catch (IllegalArgumentException ex) { | ||
assertTrue(ex.getMessage().contains("Invalid spiffe uri validator: com.yahoo.athenz.common.server.spiffe.impl.InvalidClass")); | ||
} | ||
System.clearProperty("athenz.zts.spiffe_uri_validator_classes"); | ||
} | ||
} |
53 changes: 53 additions & 0 deletions
53
...er_common/src/test/java/com/yahoo/athenz/common/server/spiffe/SpiffeUriValidatorTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
/* | ||
* Copyright The Athenz Authors | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
package com.yahoo.athenz.common.server.spiffe; | ||
|
||
import org.testng.annotations.Test; | ||
|
||
import static org.testng.Assert.assertFalse; | ||
import static org.testng.Assert.assertTrue; | ||
|
||
public class SpiffeUriValidatorTest { | ||
|
||
@Test | ||
public void testValidate() { | ||
|
||
final String trustDomain = "athenz.io"; | ||
|
||
SpiffeUriValidator validator = new SpiffeUriValidator() { | ||
@Override | ||
public boolean validateServiceCertUri(String spiffeUri, String domainName, String serviceName, String namespace) { | ||
final String expectedUri = String.format("spiffe://%s/ns/%s/sa/%s.%s", trustDomain, namespace, | ||
domainName, serviceName); | ||
return spiffeUri.equals(expectedUri); | ||
} | ||
|
||
@Override | ||
public boolean validateRoleCertUri(String spiffeUri, String domainName, String roleName) { | ||
final String expectedUri = String.format("spiffe://%s/ns/%s/ra/%s", trustDomain, | ||
domainName, roleName); | ||
return spiffeUri.equals(expectedUri); | ||
} | ||
}; | ||
|
||
assertTrue(validator.validateServiceCertUri("spiffe://athenz.io/ns/prod/sa/athenz.api", "athenz", "api", "prod")); | ||
assertFalse(validator.validateServiceCertUri("spiffe://athenz.io/ns/prod/sa/athenz.api", "athenz", "api", "dev")); | ||
|
||
assertTrue(validator.validateRoleCertUri("spiffe://athenz.io/ns/athenz/ra/readers", "athenz", "readers")); | ||
assertFalse(validator.validateRoleCertUri("spiffe://athenz.io/ns/athenz/ra/readers", "athenz", "writers")); | ||
} | ||
} |
Oops, something went wrong.