/** * Copyright 2017 Netflix, Inc. * * 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.netflix.raigad.resources; import com.google.inject.Inject; import com.netflix.raigad.identity.IMembership; import org.apache.commons.validator.routines.InetAddressValidator; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.ws.rs.*; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import java.util.Collections; /** * This http endpoint allows direct updates (adding/removing) (CIDR) IP addresses and port * ranges to the security group for this app. */ @Path("/v1/secgroup") @Produces(MediaType.TEXT_PLAIN) public class SecurityGroupAdmin { private static final Logger log = LoggerFactory.getLogger(SecurityGroupAdmin.class); private static final Integer DEFAULT_MASK = 32; private final IMembership membership; @Inject public SecurityGroupAdmin(IMembership membership) { this.membership = membership; } @POST public Response addACL( @QueryParam("ip") String ipAddress, @QueryParam("mask") Integer mask, @QueryParam("fromPort") int fromPort, @QueryParam("toPort") int toPort) { if (!InetAddressValidator.getInstance().isValid(ipAddress)) { log.error("Invalid IP address", ipAddress); return Response.status(Response.Status.BAD_REQUEST).build(); } if (mask == null || mask < 8) { log.info("IP mask is too wide or not provided, using /32"); mask = DEFAULT_MASK; } try { membership.addACL(Collections.singletonList(String.format("%s/%d", ipAddress, mask)), fromPort, toPort); } catch (Exception e) { log.error("Error adding ACL to a security group", e); return Response.serverError().build(); } return Response.ok().build(); } @DELETE public Response removeACL( @QueryParam("ip") String ipAddress, @QueryParam("mask") Integer mask, @QueryParam("fromPort") int fromPort, @QueryParam("toPort") int toPort) { if (!InetAddressValidator.getInstance().isValid(ipAddress)) { log.error("Invalid IP address", ipAddress); return Response.status(Response.Status.BAD_REQUEST).build(); } if (mask == null) { log.info("IP mask not provided, using /32"); mask = DEFAULT_MASK; } try { membership.removeACL(Collections.singletonList(String.format("%s/%d", ipAddress, mask)), fromPort, toPort); } catch (Exception e) { log.error("Error removing ACL from a security group", e); return Response.serverError().build(); } return Response.ok().build(); } }