How to create a web interface to modify your AWS Security Group

Hello!

On top of developing and designing websites for clients in and around Toronto, we also do managed and dedicated web hosting. This includes managing AWS Cloud infrastructure for our clients.

When implementing infrastructure in general terms, it is generally accepted to take the approach to lock down as much as possible with respect to firewall ports and public exposure of services on your instance or server. This means anything that doesn’t need to be exposed publicly should be blocked and closed off at the firewall level.

Sometimes, especially with servers and services that are used by many end-users, it is difficult to find a balance between security and convenience. This simple web interface was created to address that balance and hopefully sharing it will help other people in similar scenarios find that balance too.

I’ll walk through the web interface and break it into chunks to explain how everything works. Or you can dive in right away! Check out our GitHub repository.

Install the AWS PHP SDK

This is what you need to do first! Amazon maintains pretty thorough documentation that is much better than anything we could write here. Head on over there and follow the steps outlined there. Make sure to install in the document root of the site you are ultimately implementing.

Setup apache or nginx

What you’re going to want to do is set up a virtual host site in apache or nginx. Make sure that the site uses SSL (self signed should be okay). This is important because we’re going to be using HTTP authentication as a barrier to access the page itself. Different methods for authenticating and protecting access could also be explored, however HTTP authentication is the easiest to set up in this scenario.

                Order allow,deny
                Allow from all
                AuthName "Secure Access"
                AuthType Basic
                AuthUserFile /etc/httpd/htpasswd/htpasswd.secure.users
                Require valid-user
                AllowOverride None

The above is standard apache configuration directives to lock down the directory in your virtual host with authentication as a requirement. For nginx its much simpler :

                auth_basic "Secure Access";
                auth_basic_user_file /etc/nginx/htpasswd/htpasswd.secure.users;

Create AWS IAM Security Credentials

This PHP web interface needs to authenticate with your AWS account in order to manipulate your security groups. This means you need to create an IAM User + security credential for the script to use.

It would be advisable, when creating the access credential, to lock it down in terms of permissions as much as you possibly can. This means that ideally the credentials should only need to access the services necessary to manipulate the services that are within the scope. This will mitigate security exposure to other services in your AWS account.

Through trial and error, we have already gone through and generated a policy configuration to restrict access to security groups :

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "Stmt1467303214000",
            "Effect": "Allow",
            "Action": [
                "ec2:AuthorizeSecurityGroupEgress",
                "ec2:AuthorizeSecurityGroupIngress",
                "ec2:CreateSecurityGroup",
                "ec2:DeleteSecurityGroup",
                "ec2:DescribeInstanceAttribute",
                "ec2:DescribeInstanceStatus",
                "ec2:DescribeInstances",
                "ec2:DescribeNetworkAcls",
                "ec2:DescribeSecurityGroups",
                "ec2:RevokeSecurityGroupEgress",
                "ec2:RevokeSecurityGroupIngress"
            ],
            "Resource": [
                "*"
            ]
        }
    ]
}

Your free to use the above policy configuration. You could also go a bit further and lock down the “Resource” section by specifying a specific security group that this policy will allow access for, further mitigating potential exposure.

The web interface to AWS Security Groups

This is where the interesting stuff is! Using the AWS PHP SDK is again well documented here. The script itself has two “modes” : Regular and http POST processing. The interface consists of a simple input form where you enter your IP address and hit submit.

The input box auto populates with your current IP (to make something already easy even easier) :

// Get Users IP
if (isset($_SERVER['HTTP_X_FORWARDED_FOR']) && $_SERVER['HTTP_X_FORWARDED_FOR']) {
    $client_ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
} else {
    $client_ip = $_SERVER['REMOTE_ADDR'];
}

I also use a common function that I’ve used elsewhere and by no means should be considered “bulletproof” but is a good start to mitigating potential XSS and injection vulnerabilities :

// Cross Site Script  & Code Injection Sanitization
function xss_cleaner($input_str) {
    $return_str = str_replace( array('<',';','|','&','>',"'",'"',')','('), array('<',':','|','&','>',''','"',')','('), $input_str );
    $return_str = str_ireplace( '%3Cscript', '', $return_str );
    return $return_str;
}

The SDK already should be doing a good job at sanitizing input, but its always a good idea to protect as much as possible with the attitude that everything is an attack vector.

The “meat” of the code here is the HTTP POST processing. If you post the input box, it will take that value, sanitize it and submit it to AWS via the API to modify your security group.

// Process form submission
if (!empty($_POST['ip_address'])) {
        $clean_ip = xss_cleaner($_POST['ip_address']) . '/32';
        $ec2Client = Ec2Client::factory(array(
                'profile' => 'aws-project1',
                'region' => 'us-east-1' // (e.g., us-east-1)
        ));
        // Set ingress rules for the security group
        try {
                $ec2Client->authorizeSecurityGroupIngress(array(
                        'GroupName'     => 'WWW',
                        'IpPermissions' => array(
                                array(
                                        'IpProtocol' => 'tcp',
                                        'FromPort'   => 21,
                                        'ToPort'     => 21,
                                        'IpRanges'   => array(
                                                array('CidrIp' => $clean_ip)
                                                ),
                                        )
                                )
                        ));
        } catch (ec2 $e) {
                $result = $e->getMessage();
        }
}
?>

You can see that we’re establishing an ec2Client connection, using the “profile” directive to securely load the AWS credentials outside of the document root folder (i.e. “~/.aws/credentials”). Then we simply establish the name of the security group and the rule to add. In this case we are adding FTP inbound (tcp port 21) rules. Since it accepts an array as input in terms of rules, you can add as many rules in one shot as you want.

We are also catching any error and storing it in the $result variable. This is useful for dynamically displaying errors and return messages from interacting with the AWS API. We like jQuery because it will allow things to be displayed or faded in dynamically without having to reload the page.

What we do at the bottom of the script is check for the $result variable and if its not empty, append some jQuery at the bottom to display the message.






Its interesting because we are checking two conditions : if $result is empty, and if $result is empty AND there was a POST submitted. The latter condition would be if the submission of the security group change was actually successful. Anything else will return the $result for a verbose displaying of the error.

We use CSS to display the error message using a green color if successful and a red color if an error happened :

#message {
        text-align:center;
        padding-top:25px;
        color: #800000;
        font-size:12px;
}
.success {
        color: #10C407 !important;
}

That’s about it for the script! This could definitely be expanded on to provide different capabilities to dynamically interact with your AWS services in a more secure and “locked down” way. Security should always be considered first, so additional elements and logging strategies for auditing and security purposes is recommended.

aws-php

Subscribe
Notify of
guest

0 Comments
Inline Feedbacks
View all comments