com.nike.cerberus.module.CerberusModule.java Source code

Java tutorial

Introduction

Here is the source code for com.nike.cerberus.module.CerberusModule.java

Source

/*
 * Copyright (c) 2016 Nike, 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.nike.cerberus.module;

import com.amazonaws.AmazonWebServiceClient;
import com.amazonaws.ClientConfiguration;
import com.amazonaws.auth.AWSCredentialsProviderChain;
import com.amazonaws.auth.EnvironmentVariableCredentialsProvider;
import com.amazonaws.auth.InstanceProfileCredentialsProvider;
import com.amazonaws.auth.STSAssumeRoleSessionCredentialsProvider;
import com.amazonaws.auth.SystemPropertiesCredentialsProvider;
import com.amazonaws.auth.profile.ProfileCredentialsProvider;
import com.amazonaws.regions.Region;
import com.amazonaws.regions.Regions;
import com.amazonaws.services.autoscaling.AmazonAutoScaling;
import com.amazonaws.services.autoscaling.AmazonAutoScalingClient;
import com.amazonaws.services.cloudformation.AmazonCloudFormation;
import com.amazonaws.services.cloudformation.AmazonCloudFormationClient;
import com.amazonaws.services.ec2.AmazonEC2;
import com.amazonaws.services.ec2.AmazonEC2Client;
import com.amazonaws.services.identitymanagement.AmazonIdentityManagement;
import com.amazonaws.services.identitymanagement.AmazonIdentityManagementClient;
import com.amazonaws.services.kms.AWSKMS;
import com.amazonaws.services.kms.AWSKMSClient;
import com.amazonaws.services.lambda.AWSLambda;
import com.amazonaws.services.lambda.AWSLambdaClient;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.AmazonS3Client;
import com.amazonaws.services.s3.model.Bucket;
import com.amazonaws.services.securitytoken.AWSSecurityTokenService;
import com.amazonaws.services.securitytoken.AWSSecurityTokenServiceClient;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.PropertyNamingStrategy;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.github.mustachejava.DefaultMustacheFactory;
import com.github.mustachejava.MustacheFactory;
import com.google.inject.AbstractModule;
import com.google.inject.Provides;
import com.nike.cerberus.ConfigConstants;
import com.nike.cerberus.command.ProxyDelegate;
import com.nike.cerberus.domain.EnvironmentMetadata;
import com.nike.cerberus.util.TokenSupplier;
import com.nike.cerberus.util.UuidSupplier;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.inject.Named;
import javax.inject.Singleton;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.util.List;
import java.util.Optional;
import java.util.UUID;

/**
 * Guice module for enabling DI.
 */
public class CerberusModule extends AbstractModule {

    public static final String CF_OBJECT_MAPPER = "cloudformationObjectMapper";

    public static final String CONFIG_OBJECT_MAPPER = "configObjectMapper";

    public static final String CERBERUS_ASSUME_ROLE_ARN = "CERBERUS_ASSUME_ROLE_ARN";

    public static final String CERBERUS_ASSUME_ROLE_EXTERNAL_ID = "CERBERUS_ASSUME_ROLE_EXTERNAL_ID";

    private final Logger logger = LoggerFactory.getLogger(getClass());

    private final ProxyDelegate proxyDelegate;

    private final String environmentName;

    private final String regionName;

    public CerberusModule(ProxyDelegate proxyDelegate, String environmentName, String regionName) {
        this.proxyDelegate = proxyDelegate;
        this.environmentName = environmentName;
        this.regionName = regionName;
    }

    /**
     * Binds all the Amazon services used.
     */
    @Override
    protected void configure() {
        final Region region = Region.getRegion(Regions.fromName(regionName));
        bind(AmazonEC2.class).toInstance(createAmazonClientInstance(AmazonEC2Client.class, region));
        bind(AmazonCloudFormation.class)
                .toInstance(createAmazonClientInstance(AmazonCloudFormationClient.class, region));
        bind(AmazonIdentityManagement.class)
                .toInstance(createAmazonClientInstance(AmazonIdentityManagementClient.class, region));
        bind(AWSKMS.class).toInstance(createAmazonClientInstance(AWSKMSClient.class, region));
        bind(AmazonS3.class).toInstance(createAmazonClientInstance(AmazonS3Client.class, region));
        bind(AmazonAutoScaling.class).toInstance(createAmazonClientInstance(AmazonAutoScalingClient.class, region));
        bind(AWSSecurityTokenService.class)
                .toInstance(createAmazonClientInstance(AWSSecurityTokenServiceClient.class, region));
        bind(AWSLambda.class).toInstance(createAmazonClientInstance(AWSLambdaClient.class, region));
    }

    /**
     * Object mapper for handling CloudFormation parameters and outputs.
     *
     * @return Object mapper
     */
    @Provides
    @Singleton
    @Named(CF_OBJECT_MAPPER)
    public ObjectMapper cloudFormationObjectMapper() {
        final ObjectMapper om = new ObjectMapper();
        om.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        om.setSerializationInclusion(JsonInclude.Include.NON_ABSENT);
        return om;
    }

    /**
     * Object mapper for handling configuration objects in the config bucket.
     *
     * @return Object mapper
     */
    @Provides
    @Singleton
    @Named(CONFIG_OBJECT_MAPPER)
    public ObjectMapper configObjectMapper() {
        final ObjectMapper om = new ObjectMapper();
        om.findAndRegisterModules();
        om.setPropertyNamingStrategy(PropertyNamingStrategy.SNAKE_CASE);
        om.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
        om.enable(SerializationFeature.WRITE_EMPTY_JSON_ARRAYS);
        om.enable(SerializationFeature.INDENT_OUTPUT);
        om.enable(SerializationFeature.ORDER_MAP_ENTRIES_BY_KEYS);
        om.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        return om;
    }

    /**
     * Environment metadata object for describing the environment being executed against.
     *
     * @return Environment metadata
     */
    @Provides
    @Singleton
    public EnvironmentMetadata environmentMetadata() {
        final Optional<String> bucketName = findBucket(environmentName);
        final EnvironmentMetadata environmentMetadata = new EnvironmentMetadata(environmentName, regionName);

        if (bucketName.isPresent()) {
            environmentMetadata.setBucketName(bucketName.get());
        } else {
            logger.warn("Unable to determine the environment bucket for {}.", environmentName);
        }

        return environmentMetadata;
    }

    @Provides
    @Singleton
    public MustacheFactory mustacheFactory() {
        return new DefaultMustacheFactory();
    }

    @Provides
    @Singleton
    public TokenSupplier tokenSupplier() {
        return new TokenSupplier();
    }

    @Provides
    @Singleton
    public UuidSupplier uuidSupplier() {
        return new UuidSupplier();
    }

    @Provides
    @Singleton
    public Proxy proxy() {
        final Proxy.Type type = proxyDelegate.getProxyType();

        if (type == Proxy.Type.DIRECT) {
            return Proxy.NO_PROXY;
        }

        final String host = proxyDelegate.getProxyHost();
        final Integer port = proxyDelegate.getProxyPort();

        if (StringUtils.isBlank(host) || port == null) {
            logger.warn("Invalid proxy settings, ignoring...");
            return Proxy.NO_PROXY;
        }

        return new Proxy(type, new InetSocketAddress(host, port));
    }

    private Optional<String> findBucket(final String environmentName) {
        AmazonS3Client s3Client = new AmazonS3Client();
        List<Bucket> buckets = s3Client.listBuckets();

        String envBucket = null;
        for (final Bucket bucket : buckets) {
            if (StringUtils.contains(bucket.getName(), ConfigConstants.CONFIG_BUCKET_KEY)) {
                String[] parts = bucket.getName().split("-");
                if (StringUtils.equalsIgnoreCase(environmentName, parts[0])) {
                    envBucket = bucket.getName();
                    break;
                }
            }
        }

        return Optional.ofNullable(envBucket);
    }

    private static <M extends AmazonWebServiceClient> M createAmazonClientInstance(Class<M> clientClass,
            Region region) {
        String cerberusRoleToAssume = System.getenv(CERBERUS_ASSUME_ROLE_ARN) != null
                ? System.getenv(CERBERUS_ASSUME_ROLE_ARN)
                : "";
        String cerberusRoleToAssumeExternalId = System.getenv(CERBERUS_ASSUME_ROLE_EXTERNAL_ID) != null
                ? System.getenv(CERBERUS_ASSUME_ROLE_EXTERNAL_ID)
                : "";

        STSAssumeRoleSessionCredentialsProvider sTSAssumeRoleSessionCredentialsProvider = new STSAssumeRoleSessionCredentialsProvider.Builder(
                cerberusRoleToAssume, UUID.randomUUID().toString()).withExternalId(cerberusRoleToAssumeExternalId)
                        .build();

        AWSCredentialsProviderChain chain = new AWSCredentialsProviderChain(
                new EnvironmentVariableCredentialsProvider(), new SystemPropertiesCredentialsProvider(),
                new ProfileCredentialsProvider(), sTSAssumeRoleSessionCredentialsProvider,
                new InstanceProfileCredentialsProvider());
        return region.createClient(clientClass, chain, new ClientConfiguration());
    }
}