Istio Authorization Policies provide service-level access control in Kubernetes environments. This guide covers how to implement, test, and manage Istio Authorization Policies with Java applications.
Overview and Concepts
Istio Authorization Policy Components:
- Workload Selectors: Target specific services/pods
- Rules: Define access control rules
- Sources: Specify who can access (principals, namespaces, IP blocks)
- Operations: Define what actions are allowed (HTTP methods, paths)
- Conditions: Additional constraints (headers, JWT claims)
Key Benefits:
- Service Mesh Security: Enforce security at the network layer
- Zero-Trust Networking: Default deny, explicit allow
- Flexible Policies: Rich condition matching
- Kubernetes Native: CRD-based configuration
Dependencies and Setup
Maven Dependencies
<properties>
<spring-boot.version>3.1.0</spring-boot.version>
<kubernetes-client.version>6.7.2</kubernetes-client.version>
<istio-client.version>1.18.0</istio-client.version>
</properties>
<dependencies>
<!-- Spring Boot -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>${spring-boot.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
<version>${spring-boot.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
<version>${spring-boot.version}</version>
</dependency>
<!-- Kubernetes Client -->
<dependency>
<groupId>io.fabric8</groupId>
<artifactId>kubernetes-client</artifactId>
<version>${kubernetes-client.version}</version>
</dependency>
<!-- Istio Client -->
<dependency>
<groupId>io.fabric8</groupId>
<artifactId>istio-client</artifactId>
<version>${istio-client.version}</version>
</dependency>
<!-- YAML Processing -->
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-yaml</artifactId>
<version>2.15.2</version>
</dependency>
<!-- Validation -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
<version>${spring-boot.version}</version>
</dependency>
</dependencies>
Application Configuration
# application.yml
istio:
authorization:
enabled: true
namespace: ${NAMESPACE:default}
service-account: ${SERVICE_ACCOUNT:my-service}
auto-create-policies: true
spring:
application:
name: user-service
management:
endpoints:
web:
exposure:
include: health,info,metrics,istio-policies
endpoint:
health:
show-details: always
logging:
level:
com.example.istio: DEBUG
Configuration Properties
@Configuration
@ConfigurationProperties(prefix = "istio.authorization")
@Data
public class IstioAuthorizationProperties {
private boolean enabled = true;
private String namespace = "default";
private String serviceAccount;
private boolean autoCreatePolicies = true;
private PolicyDefaults defaults = new PolicyDefaults();
@Data
public static class PolicyDefaults {
private String action = "ALLOW";
private int priority = 1000;
private boolean auditEnabled = false;
}
}
Core Authorization Policy Models
1. Istio Authorization Policy Models
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class IstioAuthorizationPolicy {
private String name;
private String namespace;
private String serviceAccount;
private PolicySpec spec;
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public static class PolicySpec {
private Selector selector;
private List<Rule> rules;
private String action;
private List<Rule> denyRules;
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public static class Selector {
private Map<String, String> matchLabels;
}
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public static class Rule {
private List<Source> from;
private List<To> to;
private List<When> when;
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public static class Source {
private List<Principal> principals;
private List<Namespace> namespaces;
private List<IPBlock> ipBlocks;
private List<RequestPrincipal> requestPrincipals;
private List<NotSource> notSources;
}
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public static class To {
private List<Operation> operations;
private List<NotOperation> notOperations;
}
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public static class When {
private String key;
private List<String> values;
private List<String> notValues;
}
}
}
}
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class Principal {
private String name;
private String namespace;
}
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class Namespace {
private String name;
}
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class IPBlock {
private String cidr;
private List<String> except;
}
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class RequestPrincipal {
private String value;
}
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class Operation {
private List<String> methods;
private List<String> paths;
private List<String> hosts;
private List<String> ports;
}
// NotSource, NotOperation are similar to their positive counterparts
2. Policy Request/Response Models
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class PolicyRequest {
private String policyName;
private String serviceName;
private List<AccessRule> allowRules;
private List<AccessRule> denyRules;
private String action;
private Integer priority;
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public static class AccessRule {
private List<String> sources;
private List<String> methods;
private List<String> paths;
private Map<String, String> conditions;
}
}
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class PolicyResponse {
private String policyName;
private String status;
private String message;
private Instant createdAt;
private String yamlDefinition;
}
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class PolicyValidationResult {
private boolean valid;
private List<String> errors;
private List<String> warnings;
public static PolicyValidationResult valid() {
return PolicyValidationResult.builder().valid(true).errors(new ArrayList<>()).warnings(new ArrayList<>()).build();
}
public static PolicyValidationResult invalid(String error) {
return PolicyValidationResult.builder().valid(false).errors(List.of(error)).warnings(new ArrayList<>()).build();
}
}
Istio Policy Service
1. Core Policy Management Service
@Service
@Slf4j
public class IstioAuthorizationPolicyService {
private final IstioAuthorizationProperties properties;
private final KubernetesClient kubernetesClient;
private final ObjectMapper yamlMapper;
public IstioAuthorizationPolicyService(IstioAuthorizationProperties properties,
KubernetesClient kubernetesClient) {
this.properties = properties;
this.kubernetesClient = kubernetesClient;
this.yamlMapper = new ObjectMapper(new YAMLFactory());
}
public PolicyResponse createPolicy(PolicyRequest request) {
log.info("Creating Istio Authorization Policy: {}", request.getPolicyName());
try {
// Validate policy request
PolicyValidationResult validation = validatePolicyRequest(request);
if (!validation.isValid()) {
return PolicyResponse.builder()
.policyName(request.getPolicyName())
.status("FAILED")
.message("Validation failed: " + String.join(", ", validation.getErrors()))
.createdAt(Instant.now())
.build();
}
// Convert to Istio Authorization Policy
IstioAuthorizationPolicy policy = convertToIstioPolicy(request);
// Create Kubernetes resource
createKubernetesResource(policy);
log.info("Successfully created Istio Authorization Policy: {}", request.getPolicyName());
return PolicyResponse.builder()
.policyName(request.getPolicyName())
.status("SUCCESS")
.message("Policy created successfully")
.createdAt(Instant.now())
.yamlDefinition(generateYamlDefinition(policy))
.build();
} catch (Exception e) {
log.error("Failed to create Istio Authorization Policy: {}", request.getPolicyName(), e);
return PolicyResponse.builder()
.policyName(request.getPolicyName())
.status("FAILED")
.message("Creation failed: " + e.getMessage())
.createdAt(Instant.now())
.build();
}
}
public PolicyResponse updatePolicy(PolicyRequest request) {
log.info("Updating Istio Authorization Policy: {}", request.getPolicyName());
try {
// Check if policy exists
if (!policyExists(request.getPolicyName())) {
return PolicyResponse.builder()
.policyName(request.getPolicyName())
.status("FAILED")
.message("Policy not found")
.createdAt(Instant.now())
.build();
}
// Delete existing policy
deletePolicy(request.getPolicyName());
// Create new policy
return createPolicy(request);
} catch (Exception e) {
log.error("Failed to update Istio Authorization Policy: {}", request.getPolicyName(), e);
return PolicyResponse.builder()
.policyName(request.getPolicyName())
.status("FAILED")
.message("Update failed: " + e.getMessage())
.createdAt(Instant.now())
.build();
}
}
public boolean deletePolicy(String policyName) {
log.info("Deleting Istio Authorization Policy: {}", policyName);
try {
return kubernetesClient.resources(io.fabric8.istio.api.security.v1beta1.AuthorizationPolicy.class)
.inNamespace(properties.getNamespace())
.withName(policyName)
.delete();
} catch (Exception e) {
log.error("Failed to delete Istio Authorization Policy: {}", policyName, e);
return false;
}
}
public List<String> listPolicies() {
log.debug("Listing Istio Authorization Policies in namespace: {}", properties.getNamespace());
try {
return kubernetesClient.resources(io.fabric8.istio.api.security.v1beta1.AuthorizationPolicy.class)
.inNamespace(properties.getNamespace())
.list()
.getItems()
.stream()
.map(policy -> policy.getMetadata().getName())
.collect(Collectors.toList());
} catch (Exception e) {
log.error("Failed to list Istio Authorization Policies", e);
return Collections.emptyList();
}
}
public Optional<IstioAuthorizationPolicy> getPolicy(String policyName) {
log.debug("Getting Istio Authorization Policy: {}", policyName);
try {
io.fabric8.istio.api.security.v1beta1.AuthorizationPolicy policy =
kubernetesClient.resources(io.fabric8.istio.api.security.v1beta1.AuthorizationPolicy.class)
.inNamespace(properties.getNamespace())
.withName(policyName)
.get();
return policy != null ? Optional.of(convertFromKubernetesResource(policy)) : Optional.empty();
} catch (Exception e) {
log.error("Failed to get Istio Authorization Policy: {}", policyName, e);
return Optional.empty();
}
}
public PolicyValidationResult validatePolicy(PolicyRequest request) {
List<String> errors = new ArrayList<>();
List<String> warnings = new ArrayList<>();
// Validate policy name
if (request.getPolicyName() == null || request.getPolicyName().trim().isEmpty()) {
errors.add("Policy name is required");
} else if (!request.getPolicyName().matches("^[a-z0-9-]+$")) {
errors.add("Policy name must contain only lowercase letters, numbers, and hyphens");
}
// Validate service name
if (request.getServiceName() == null || request.getServiceName().trim().isEmpty()) {
errors.add("Service name is required");
}
// Validate action
if (request.getAction() != null &&
!List.of("ALLOW", "DENY", "AUDIT", "CUSTOM").contains(request.getAction().toUpperCase())) {
errors.add("Invalid action. Must be one of: ALLOW, DENY, AUDIT, CUSTOM");
}
// Validate rules
if ((request.getAllowRules() == null || request.getAllowRules().isEmpty()) &&
(request.getDenyRules() == null || request.getDenyRules().isEmpty())) {
warnings.add("Policy has no rules defined - this may not have the intended effect");
}
// Validate priority
if (request.getPriority() != null && (request.getPriority() < 0 || request.getPriority() > 1000000)) {
errors.add("Priority must be between 0 and 1000000");
}
return PolicyValidationResult.builder()
.valid(errors.isEmpty())
.errors(errors)
.warnings(warnings)
.build();
}
private PolicyValidationResult validatePolicyRequest(PolicyRequest request) {
// Basic validation
PolicyValidationResult basicValidation = validatePolicy(request);
if (!basicValidation.isValid()) {
return basicValidation;
}
// Check for policy name conflicts
if (policyExists(request.getPolicyName())) {
return PolicyValidationResult.invalid("Policy with name '" + request.getPolicyName() + "' already exists");
}
return PolicyValidationResult.valid();
}
private boolean policyExists(String policyName) {
return getPolicy(policyName).isPresent();
}
private IstioAuthorizationPolicy convertToIstioPolicy(PolicyRequest request) {
return IstioAuthorizationPolicy.builder()
.name(request.getPolicyName())
.namespace(properties.getNamespace())
.serviceAccount(properties.getServiceAccount())
.spec(buildPolicySpec(request))
.build();
}
private IstioAuthorizationPolicy.PolicySpec buildPolicySpec(PolicyRequest request) {
IstioAuthorizationPolicy.PolicySpec.PolicySpecBuilder specBuilder =
IstioAuthorizationPolicy.PolicySpec.builder();
// Set selector
specBuilder.selector(buildSelector(request.getServiceName()));
// Set action
specBuilder.action(request.getAction() != null ? request.getAction() : properties.getDefaults().getAction());
// Build allow rules
if (request.getAllowRules() != null && !request.getAllowRules().isEmpty()) {
specBuilder.rules(buildRules(request.getAllowRules()));
}
// Build deny rules
if (request.getDenyRules() != null && !request.getDenyRules().isEmpty()) {
specBuilder.denyRules(buildRules(request.getDenyRules()));
}
return specBuilder.build();
}
private IstioAuthorizationPolicy.PolicySpec.Selector buildSelector(String serviceName) {
return IstioAuthorizationPolicy.PolicySpec.Selector.builder()
.matchLabels(Map.of(
"app", serviceName,
"version", "v1"
))
.build();
}
private List<IstioAuthorizationPolicy.PolicySpec.Rule> buildRules(List<PolicyRequest.AccessRule> accessRules) {
return accessRules.stream()
.map(this::buildRule)
.collect(Collectors.toList());
}
private IstioAuthorizationPolicy.PolicySpec.Rule buildRule(PolicyRequest.AccessRule accessRule) {
IstioAuthorizationPolicy.PolicySpec.Rule.RuleBuilder ruleBuilder =
IstioAuthorizationPolicy.PolicySpec.Rule.builder();
// Build sources
if (accessRule.getSources() != null && !accessRule.getSources().isEmpty()) {
ruleBuilder.from(buildSources(accessRule.getSources()));
}
// Build operations
if (accessRule.getMethods() != null || accessRule.getPaths() != null) {
ruleBuilder.to(buildOperations(accessRule.getMethods(), accessRule.getPaths()));
}
// Build conditions
if (accessRule.getConditions() != null && !accessRule.getConditions().isEmpty()) {
ruleBuilder.when(buildConditions(accessRule.getConditions()));
}
return ruleBuilder.build();
}
private List<IstioAuthorizationPolicy.PolicySpec.Rule.Source> buildSources(List<String> sources) {
return sources.stream()
.map(this::parseSource)
.collect(Collectors.toList());
}
private IstioAuthorizationPolicy.PolicySpec.Rule.Source parseSource(String source) {
// Parse source string format: "principal:cluster.local/ns/default/sa/service-account"
// or "namespace:default" or "ip:192.168.1.0/24"
if (source.startsWith("principal:")) {
return IstioAuthorizationPolicy.PolicySpec.Rule.Source.builder()
.principals(List.of(Principal.builder().name(source.substring(10)).build()))
.build();
} else if (source.startsWith("namespace:")) {
return IstioAuthorizationPolicy.PolicySpec.Rule.Source.builder()
.namespaces(List.of(Namespace.builder().name(source.substring(10)).build()))
.build();
} else if (source.startsWith("ip:")) {
return IstioAuthorizationPolicy.PolicySpec.Rule.Source.builder()
.ipBlocks(List.of(IPBlock.builder().cidr(source.substring(3)).build()))
.build();
} else {
// Default to principal
return IstioAuthorizationPolicy.PolicySpec.Rule.Source.builder()
.principals(List.of(Principal.builder().name(source).build()))
.build();
}
}
private List<IstioAuthorizationPolicy.PolicySpec.Rule.To> buildOperations(List<String> methods, List<String> paths) {
Operation operation = Operation.builder()
.methods(methods != null ? methods : List.of("*"))
.paths(paths != null ? paths : List.of("*"))
.build();
return List.of(
IstioAuthorizationPolicy.PolicySpec.Rule.To.builder()
.operations(List.of(operation))
.build()
);
}
private List<IstioAuthorizationPolicy.PolicySpec.Rule.When> buildConditions(Map<String, String> conditions) {
return conditions.entrySet().stream()
.map(entry -> IstioAuthorizationPolicy.PolicySpec.Rule.When.builder()
.key(entry.getKey())
.values(List.of(entry.getValue()))
.build())
.collect(Collectors.toList());
}
private void createKubernetesResource(IstioAuthorizationPolicy policy) {
io.fabric8.istio.api.security.v1beta1.AuthorizationPolicy k8sPolicy =
convertToKubernetesResource(policy);
kubernetesClient.resources(io.fabric8.istio.api.security.v1beta1.AuthorizationPolicy.class)
.inNamespace(policy.getNamespace())
.resource(k8sPolicy)
.create();
}
private io.fabric8.istio.api.security.v1beta1.AuthorizationPolicy convertToKubernetesResource(
IstioAuthorizationPolicy policy) {
io.fabric8.istio.api.security.v1beta1.AuthorizationPolicy k8sPolicy =
new io.fabric8.istio.api.security.v1beta1.AuthorizationPolicy();
// Set metadata
ObjectMeta metadata = new ObjectMeta();
metadata.setName(policy.getName());
metadata.setNamespace(policy.getNamespace());
k8sPolicy.setMetadata(metadata);
// Set spec
io.fabric8.istio.api.security.v1beta1.AuthorizationPolicySpec spec =
new io.fabric8.istio.api.security.v1beta1.AuthorizationPolicySpec();
// Convert selector
if (policy.getSpec().getSelector() != null) {
Map<String, String> matchLabels = policy.getSpec().getSelector().getMatchLabels();
if (matchLabels != null) {
spec.setSelector(new io.fabric8.istio.api.security.v1beta1.WorkloadSelector(matchLabels));
}
}
// Convert rules
if (policy.getSpec().getRules() != null) {
spec.setRules(convertRules(policy.getSpec().getRules()));
}
// Convert action
if (policy.getSpec().getAction() != null) {
spec.setAction(io.fabric8.istio.api.security.v1beta1.AuthorizationPolicyAction.valueOf(
policy.getSpec().getAction()));
}
k8sPolicy.setSpec(spec);
return k8sPolicy;
}
private List<io.fabric8.istio.api.security.v1beta1.Rule> convertRules(
List<IstioAuthorizationPolicy.PolicySpec.Rule> rules) {
return rules.stream()
.map(this::convertRule)
.collect(Collectors.toList());
}
private io.fabric8.istio.api.security.v1beta1.Rule convertRule(
IstioAuthorizationPolicy.PolicySpec.Rule rule) {
io.fabric8.istio.api.security.v1beta1.Rule k8sRule =
new io.fabric8.istio.api.security.v1beta1.Rule();
// Convert from
if (rule.getFrom() != null) {
k8sRule.setFrom(convertFrom(rule.getFrom()));
}
// Convert to
if (rule.getTo() != null) {
k8sRule.setTo(convertTo(rule.getTo()));
}
// Convert when
if (rule.getWhen() != null) {
k8sRule.setWhen(convertWhen(rule.getWhen()));
}
return k8sRule;
}
private List<io.fabric8.istio.api.security.v1beta1.RuleFrom> convertFrom(
List<IstioAuthorizationPolicy.PolicySpec.Rule.Source> from) {
return from.stream()
.map(this::convertFromSource)
.collect(Collectors.toList());
}
private io.fabric8.istio.api.security.v1beta1.RuleFrom convertFromSource(
IstioAuthorizationPolicy.PolicySpec.Rule.Source source) {
io.fabric8.istio.api.security.v1beta1.RuleFrom ruleFrom =
new io.fabric8.istio.api.security.v1beta1.RuleFrom();
if (source.getPrincipals() != null) {
ruleFrom.setSource(new io.fabric8.istio.api.security.v1beta1.Source()
.setPrincipals(source.getPrincipals().stream()
.map(Principal::getName)
.collect(Collectors.toList())));
}
// Similar conversion for namespaces, ipBlocks, etc.
return ruleFrom;
}
// Similar conversion methods for To and When...
private IstioAuthorizationPolicy convertFromKubernetesResource(
io.fabric8.istio.api.security.v1beta1.AuthorizationPolicy k8sPolicy) {
// Reverse conversion logic
return IstioAuthorizationPolicy.builder()
.name(k8sPolicy.getMetadata().getName())
.namespace(k8sPolicy.getMetadata().getNamespace())
.build();
// Complete the conversion based on your needs
}
private String generateYamlDefinition(IstioAuthorizationPolicy policy) {
try {
return yamlMapper.writeValueAsString(convertToKubernetesResource(policy));
} catch (Exception e) {
log.error("Failed to generate YAML definition for policy: {}", policy.getName(), e);
return "Error generating YAML definition";
}
}
}
2. Policy Template Service
@Service
@Slf4j
public class IstioPolicyTemplateService {
private final IstioAuthorizationPolicyService policyService;
public IstioPolicyTemplateService(IstioAuthorizationPolicyService policyService) {
this.policyService = policyService;
}
public PolicyResponse createNamespaceIsolationPolicy(String serviceName, String namespace) {
PolicyRequest request = PolicyRequest.builder()
.policyName(serviceName + "-namespace-isolation")
.serviceName(serviceName)
.action("ALLOW")
.priority(1000)
.allowRules(List.of(
PolicyRequest.AccessRule.builder()
.sources(List.of("namespace:" + namespace))
.methods(List.of("GET", "POST", "PUT", "DELETE"))
.paths(List.of("/*"))
.build()
))
.build();
return policyService.createPolicy(request);
}
public PolicyResponse createServiceToServicePolicy(String sourceService, String targetService) {
PolicyRequest request = PolicyRequest.builder()
.policyName(targetService + "-allow-" + sourceService)
.serviceName(targetService)
.action("ALLOW")
.priority(900)
.allowRules(List.of(
PolicyRequest.AccessRule.builder()
.sources(List.of("principal:cluster.local/ns/default/sa/" + sourceService))
.methods(List.of("*"))
.paths(List.of("/*"))
.build()
))
.build();
return policyService.createPolicy(request);
}
public PolicyResponse createPublicApiPolicy(String serviceName, List<String> publicPaths) {
PolicyRequest request = PolicyRequest.builder()
.policyName(serviceName + "-public-api")
.serviceName(serviceName)
.action("ALLOW")
.priority(800)
.allowRules(List.of(
PolicyRequest.AccessRule.builder()
.sources(List.of("*")) // Allow from anywhere
.methods(List.of("GET"))
.paths(publicPaths)
.build()
))
.build();
return policyService.createPolicy(request);
}
public PolicyResponse createAdminApiPolicy(String serviceName, List<String> adminPaths) {
PolicyRequest request = PolicyRequest.builder()
.policyName(serviceName + "-admin-api")
.serviceName(serviceName)
.action("ALLOW")
.priority(1100) // Higher priority than public API
.allowRules(List.of(
PolicyRequest.AccessRule.builder()
.sources(List.of(
"principal:cluster.local/ns/kube-system/sa/admin",
"principal:cluster.local/ns/istio-system/sa/istio-ingressgateway-service-account"
))
.methods(List.of("*"))
.paths(adminPaths)
.conditions(Map.of(
"request.headers[x-admin-token]", "present"
))
.build()
))
.build();
return policyService.createPolicy(request);
}
public PolicyResponse createDenyAllPolicy(String serviceName) {
PolicyRequest request = PolicyRequest.builder()
.policyName(serviceName + "-deny-all")
.serviceName(serviceName)
.action("DENY")
.priority(1) // Lowest priority - acts as default deny
.denyRules(List.of(
PolicyRequest.AccessRule.builder()
.sources(List.of("*"))
.methods(List.of("*"))
.paths(List.of("/*"))
.build()
))
.build();
return policyService.createPolicy(request);
}
public PolicyResponse createJwtAuthPolicy(String serviceName, String issuer, List<String> protectedPaths) {
PolicyRequest request = PolicyRequest.builder()
.policyName(serviceName + "-jwt-auth")
.serviceName(serviceName)
.action("DENY")
.priority(500)
.denyRules(List.of(
PolicyRequest.AccessRule.builder()
.sources(List.of("*"))
.methods(List.of("*"))
.paths(protectedPaths)
.conditions(Map.of(
"request.auth.claims[iss]", "!" + issuer,
"request.auth.principal", "not-present"
))
.build()
))
.build();
return policyService.createPolicy(request);
}
public PolicyResponse createIpWhitelistPolicy(String serviceName, List<String> allowedIps) {
List<PolicyRequest.AccessRule> allowRules = allowedIps.stream()
.map(ip -> PolicyRequest.AccessRule.builder()
.sources(List.of("ip:" + ip))
.methods(List.of("*"))
.paths(List.of("/*"))
.build())
.collect(Collectors.toList());
PolicyRequest request = PolicyRequest.builder()
.policyName(serviceName + "-ip-whitelist")
.serviceName(serviceName)
.action("ALLOW")
.priority(700)
.allowRules(allowRules)
.build();
return policyService.createPolicy(request);
}
}
REST Controllers
1. Policy Management Controller
@RestController
@RequestMapping("/api/istio/policies")
@Validated
@Slf4j
public class IstioPolicyController {
private final IstioAuthorizationPolicyService policyService;
private final IstioPolicyTemplateService templateService;
public IstioPolicyController(IstioAuthorizationPolicyService policyService,
IstioPolicyTemplateService templateService) {
this.policyService = policyService;
this.templateService = templateService;
}
@PostMapping
public ResponseEntity<PolicyResponse> createPolicy(@Valid @RequestBody PolicyRequest request) {
log.info("Creating Istio Authorization Policy: {}", request.getPolicyName());
PolicyResponse response = policyService.createPolicy(request);
HttpStatus status = "SUCCESS".equals(response.getStatus()) ?
HttpStatus.CREATED : HttpStatus.BAD_REQUEST;
return ResponseEntity.status(status).body(response);
}
@PutMapping("/{policyName}")
public ResponseEntity<PolicyResponse> updatePolicy(@PathVariable String policyName,
@Valid @RequestBody PolicyRequest request) {
log.info("Updating Istio Authorization Policy: {}", policyName);
// Ensure policy name matches path
request.setPolicyName(policyName);
PolicyResponse response = policyService.updatePolicy(request);
HttpStatus status = "SUCCESS".equals(response.getStatus()) ?
HttpStatus.OK : HttpStatus.BAD_REQUEST;
return ResponseEntity.status(status).body(response);
}
@DeleteMapping("/{policyName}")
public ResponseEntity<BaseResponse> deletePolicy(@PathVariable String policyName) {
log.info("Deleting Istio Authorization Policy: {}", policyName);
boolean success = policyService.deletePolicy(policyName);
BaseResponse response = BaseResponse.builder()
.success(success)
.message(success ? "Policy deleted successfully" : "Failed to delete policy")
.build();
HttpStatus status = success ? HttpStatus.OK : HttpStatus.NOT_FOUND;
return ResponseEntity.status(status).body(response);
}
@GetMapping
public ResponseEntity<List<String>> listPolicies() {
log.debug("Listing all Istio Authorization Policies");
List<String> policies = policyService.listPolicies();
return ResponseEntity.ok(policies);
}
@GetMapping("/{policyName}")
public ResponseEntity<IstioAuthorizationPolicy> getPolicy(@PathVariable String policyName) {
log.debug("Getting Istio Authorization Policy: {}", policyName);
Optional<IstioAuthorizationPolicy> policy = policyService.getPolicy(policyName);
return policy.map(ResponseEntity::ok)
.orElse(ResponseEntity.notFound().build());
}
@PostMapping("/{policyName}/validate")
public ResponseEntity<PolicyValidationResult> validatePolicy(@PathVariable String policyName,
@Valid @RequestBody PolicyRequest request) {
log.debug("Validating Istio Authorization Policy: {}", policyName);
PolicyValidationResult result = policyService.validatePolicy(request);
return ResponseEntity.ok(result);
}
// Template endpoints
@PostMapping("/templates/namespace-isolation")
public ResponseEntity<PolicyResponse> createNamespaceIsolation(
@RequestParam String serviceName,
@RequestParam String namespace) {
PolicyResponse response = templateService.createNamespaceIsolationPolicy(serviceName, namespace);
return ResponseEntity.status(HttpStatus.CREATED).body(response);
}
@PostMapping("/templates/service-to-service")
public ResponseEntity<PolicyResponse> createServiceToServicePolicy(
@RequestParam String sourceService,
@RequestParam String targetService) {
PolicyResponse response = templateService.createServiceToServicePolicy(sourceService, targetService);
return ResponseEntity.status(HttpStatus.CREATED).body(response);
}
@PostMapping("/templates/public-api")
public ResponseEntity<PolicyResponse> createPublicApiPolicy(
@RequestParam String serviceName,
@RequestBody List<String> publicPaths) {
PolicyResponse response = templateService.createPublicApiPolicy(serviceName, publicPaths);
return ResponseEntity.status(HttpStatus.CREATED).body(response);
}
@PostMapping("/templates/deny-all")
public ResponseEntity<PolicyResponse> createDenyAllPolicy(@RequestParam String serviceName) {
PolicyResponse response = templateService.createDenyAllPolicy(serviceName);
return ResponseEntity.status(HttpStatus.CREATED).body(response);
}
}
@Data
class BaseResponse {
private boolean success;
private String message;
private Instant timestamp;
public BaseResponse(boolean success, String message) {
this.success = success;
this.message = message;
this.timestamp = Instant.now();
}
public static BaseResponse success(String message) {
return new BaseResponse(true, message);
}
public static BaseResponse error(String message) {
return new BaseResponse(false, message);
}
}
2. Policy Monitoring Controller
```java
@RestController
@RequestMapping("/api/istio/monitoring")
@Slf4j
public class IstioPolicyMonitoringController {
private final IstioAuthorizationPolicyService policyService;
private final KubernetesClient kubernetesClient;
public IstioPolicyMonitoringController(IstioAuthorizationPolicyService policyService,
KubernetesClient kubernetesClient) {
this.policyService = policyService;
this.kubernetesClient = kubernetesClient;
}
@GetMapping("/health")
public ResponseEntity<HealthResponse> healthCheck() {
try {
// Check Kubernetes connectivity
kubernetesClient.pods().list();
// Check policy access
policyService.listPolicies();
return ResponseEntity.ok(HealthResponse.healthy());
} catch (Exception e) {
log.error("Health check failed", e);
return ResponseEntity.status(HttpStatus.SERVICE_UNAVAILABLE)
.body(HealthResponse.unhealthy(e.getMessage()));
}
}
@GetMapping("/metrics")
public ResponseEntity<PolicyMetrics> getPolicyMetrics() {
List<String> policies = policyService.listPolicies();
PolicyMetrics metrics = PolicyMetrics.builder()
.totalPolicies(policies.size())
.policiesByNamespace(getPoliciesByNamespace())
.recentlyCreated(getRecentlyCreatedPolicies())
.build();
return ResponseEntity.ok(metrics);
}
@GetMapping("/audit")
public ResponseEntity<List<PolicyAuditEntry>> getPolicyAudit(
@RequestParam(defaultValue = "7") int days) {
// This would typically query an audit log
List<PolicyAuditEntry> auditEntries = simulatePolicyAudit(days);
return ResponseEntity.ok(auditEntries);
}
private Map<String, Integer> getPoliciesByNamespace() {
// Implementation to group policies by namespace
return Map.of("default", policyService.listPolicies().size());
}
private List<String> getRecentlyCreatedPolicies() {
// Implementation to get recently created policies
return policyService.listPolicies().stream()
.limit(10)
.collect(Collectors.toList());
}
private List<PolicyAuditEntry> simulatePolicyAudit(int days) {
// Simulate audit entries - in real implementation, query from audit log
return List.of(
PolicyAuditEntry.builder()
.policyName("example-policy")
.action("CREATE")
.user("system:serviceaccount:default:istio-policy-manager")
.timestamp(Instant.now().minus(Duration.ofDays(1)))
.success(true)
.