<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Amazon Archives | Cloudar</title>
	<atom:link href="https://cloudar.be/tag/amazon/feed/" rel="self" type="application/rss+xml" />
	<link>https://cloudar.be/tag/amazon/</link>
	<description>100% Focus On AWS // 100% Customer Obsession</description>
	<lastBuildDate>Fri, 05 Oct 2018 16:17:29 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.9.4</generator>
	<item>
		<title>Integrating Fail2Ban with AWS Network ACLs</title>
		<link>https://cloudar.be/awsblog/integrating-fail2ban-with-aws-network-acls/</link>
					<comments>https://cloudar.be/awsblog/integrating-fail2ban-with-aws-network-acls/#comments</comments>
		
		<dc:creator><![CDATA[Rutger Beyen]]></dc:creator>
		<pubDate>Fri, 05 Oct 2018 16:17:29 +0000</pubDate>
				<category><![CDATA[AWS Blog]]></category>
		<category><![CDATA[ACL]]></category>
		<category><![CDATA[Amazon]]></category>
		<category><![CDATA[Amazon Web Services]]></category>
		<category><![CDATA[AWS]]></category>
		<category><![CDATA[EC2]]></category>
		<category><![CDATA[fail2ban]]></category>
		<category><![CDATA[NACL]]></category>
		<guid isPermaLink="false">https://cloudar.be/?p=7782</guid>

					<description><![CDATA[<p>I was recently working on a project where I couldn&#8217;t lock down the Bastion instance security group ingress rule to only allow whitelisted IP addresses. Several coworkers work from home and use the Bastion to jump into backend servers and create SSH tunnels, while they did not have AWS Console access to whitelist themselves. The [&#8230;]</p>
<p>The post <a href="https://cloudar.be/awsblog/integrating-fail2ban-with-aws-network-acls/">Integrating Fail2Ban with AWS Network ACLs</a> appeared first on <a href="https://cloudar.be">Cloudar</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>I was recently working on a project where I couldn&#8217;t lock down the Bastion instance security group ingress rule to only allow whitelisted IP addresses. Several coworkers work from home and use the Bastion to jump into backend servers and create SSH tunnels, while they did not have AWS Console access to whitelist themselves. The security group ended up allowing 0.0.0.0/0 on port 22. Off course the Bastion instance would only allow ssh key based logins, but all protocols eventually have vulnerabilities. So installing multiple layers of security in depth prevents the systems from being directly affected by the latest individual vulnerabilities.</p>
<p>Combining some bits and pieces from Google allowed me to setup Fail2Ban on the Bastion instance, while the blocking of the IPs is done in AWS NACLs in stead of the local Iptables. The setup has been done on an AmazonLinux instance.</p>
<h1 id="PHC-Fail2BanwithAWSVPCACLs-Considerations">Considerations</h1>
<p>AWS NACLs by default only allow 20 ingress and 20 egress rules. This is a soft limit, and you can have it increased to 40 by opening a support case (40 seems to be the upper hard limit).</p>
<p>If fail2ban wants to add another rule while the maximum has been reached, it will block the offender in the local Iptables. Running my implementation in several environments for a few weeks now, I never had more than 4 to 5 IPs blocked at the same time. Unless you are off course the victim of a targetted ddos attack&#8230;</p>
<h1></h1>
<h1 id="PHC-Fail2BanwithAWSVPCACLs-AWSCLI">Setup the AWS CLI</h1>
<p>Make sure you have a correctly installed and working AWS CLI on the instance. Also make sure the EC2 role has the necessary permissions to modify the EC2 Network ACL. Testing it out:</p>
<p>1. Get the current MAC address of the first interface</p>
<div class="code panel pdl conf-macro output-block" data-hasbody="true" data-macro-name="code" data-macro-id="ce12476d-5e7d-4396-9bc8-2932ba849666">
<div class="codeContent panelContent pdl">
<div>
<pre class="lang:sh decode:true">INTERFACE=$(curl --silent http://169.254.169.254/latest/meta-data/network/interfaces/macs/)</pre>
</div>
</div>
</div>
<p>2. Get the subnet ID from the MAC address</p>
<pre class="lang:sh decode:true">SUBNET_ID=$(curl --silent http://169.254.169.254/latest/meta-data/network/interfaces/macs/${INTERFACE}/subnet-id)</pre>
<p>3. Get the current Network ACL ID</p>
<div class="code panel pdl conf-macro output-block" data-hasbody="true" data-macro-name="code" data-macro-id="25f89c85-841c-4adf-a6e2-0a9574e3a9ce">
<div class="codeContent panelContent pdl">
<div>
<div id="highlighter_946062" class="syntaxhighlighter sh-rdark nogutter bash">
<pre class="lang:sh decode:true">ACL_ID=$(aws ec2 describe-network-acls --filters Name=association.subnet-id,Values=$SUBNET_ID | jq '.NetworkAcls[0].Associations[0].NetworkAclId' | sed 's/"//g')</pre>
</div>
</div>
</div>
</div>
<p class="auto-cursor-target">4. Test that you can add a rule to the ACL</p>
<pre class="lang:default decode:true ">aws ec2 create-network-acl-entry --network-acl-id $ACL_ID --ingress --rule-number 1 --protocol tcp --port-range From=0,To=65535 --cidr-block 1.2.3.4/32 --rule-action deny</pre>
<p class="auto-cursor-target">5. Verify that the above IP has been blocked</p>
<div class="code panel pdl conf-macro output-block" data-hasbody="true" data-macro-name="code" data-macro-id="5683dd33-6c2b-465b-bcca-efa71da5478e">
<div class="codeContent panelContent pdl">
<div>
<div id="highlighter_116482" class="syntaxhighlighter sh-rdark nogutter bash">
<pre class="lang:sh decode:true">aws ec2 describe-network-acls --filters Name=association.network-acl-id,Values=$ACL_ID</pre>
</div>
</div>
</div>
</div>
<p class="auto-cursor-target">6. Remove the rule again</p>
<div class="code panel pdl conf-macro output-block" data-hasbody="true" data-macro-name="code" data-macro-id="17968341-e5e1-4ca9-a325-d7eb94d91883">
<div class="codeContent panelContent pdl">
<div>
<div id="highlighter_461413" class="syntaxhighlighter sh-rdark nogutter bash">
<pre class="lang:sh decode:true">aws ec2 delete-network-acl-entry --network-acl-id $ACL_ID --ingress --rule-number 1</pre>
</div>
</div>
</div>
</div>
<h1></h1>
<h1 id="PHC-Fail2BanwithAWSVPCACLs-Fail2BanAWSintegration">Fail2Ban AWS integration</h1>
<p class="auto-cursor-target">1. Install the necessary packages (if not yet present)</p>
<pre class="lang:sh decode:true ">pip install requests boto3 tabulate
yum install sqlite</pre>
<p class="auto-cursor-target">2. Create a directory to store the AWS NACL script and cd to it</p>
<pre class="lang:sh decode:true ">mkdir /opt/aws-nacl
cd /opt/aws-nacl</pre>
<p>3. Place the following content in the file aws_nacl.py in the above directory</p>
<pre class="height:50 minimize:true lang:python decode:true">"""This script is used to block and unblock IPs on Amazon EC2
network ACLs and can be used with Fail2Ban. Since only 20
inbound rules are allowed with AWS if a 'jail' is provided
the IP will be blocked on the host iptables if full"""
 
import json
import sqlite3
import argparse
import os
import pprint
import socket
import logging
import logging.handlers
import requests
import boto3
import subprocess
from tabulate import tabulate
 
#Constants
#AWS only allows 20 inbound subtract default ACL rules from 20 for max
MAX_BLOCKS = 20
#Set rule start, by default AWS ACL starts rules at 100
RULE_BASE = 1
#Set range for rules: highest rule ID that can be used
RULE_RANGE = 50
 
 
def check_block(ip,acl):
   acl = get_acl(acl)
   list = acl['NetworkAcls'][0]['Entries']
   for entry in list:
      if ip in entry["CidrBlock"]:
         return True
   return False
 
 
def get_acl(acl_id):
    """This function gets the ACL given an ec2 object and ACL id"""
    ec2 = boto3.client('ec2')
    acl_response = ec2.describe_network_acls(
        NetworkAclIds=[
            acl_id,
        ],
    )
    return acl_response
 
def print_inbound_acl(acl_id):
   blocks = []
   table = {num:name[8:] for name,num in vars(socket).items() if name.startswith("IPPROTO")}
   acl = get_acl(acl_id)
   list = acl['NetworkAcls'][0]['Entries']
   for entry in list:
     if not entry["Egress"]:
         if "PortRange" in entry:
                ports = ({"To":entry["PortRange"]["To"], "From":entry["PortRange"]["From"]})
         else:
                ports = ({"To":"", "From":""})
         if entry['Protocol'] == "-1":
                proto = "all"
         else:
                proto = table[int (entry['Protocol'])]
         blocks.append([entry['RuleNumber'],proto,entry['CidrBlock'],ports["To"],ports["From"],entry['RuleAction']])
   print "Inbound Network ACL"
   print tabulate(blocks,headers=["Rule","Protocol","CIDR","Port From","Port To","Action"])
 
def is_acl(acl):
    ec2 = boto3.client('ec2')
    try:
        ec2.describe_network_acls(
            NetworkAclIds=[
                acl,
            ],
        )
        return True
    except Exception:
        return False
 
def get_acl_id():
    ec2 = boto3.client('ec2')
    meta = "http://169.254.169.254/latest/meta-data/network/interfaces/macs/"
    mac = requests.get(meta).text
    subnet = requests.get(meta+mac+"/subnet-id").text
 
    response = ec2.describe_network_acls(
        Filters=[
            {
                'Name': 'association.subnet-id',
                'Values':[
                    subnet
                ]
            },
        ],
        DryRun=False
    )
    return response['NetworkAcls'][0]['Associations'][0]['NetworkAclId']
 
def validate_ip(ip_address):
    ip_split = ip_address.split('.')
    if len(ip_split) != 4:
        return False
    for octet in ip_split:
        if not octet.isdigit():
            return False
        octet_int = int(octet)
        if octet_int &lt; 0 or octet_int &gt; 255:
            return False
    try:
        socket.inet_aton(ip_address)
        return True
    except socket.error:
        return False
 
def sqlite_connect(file_name):
    make_table = '''CREATE TABLE if not exists blocks (id integer PRIMARY KEY AUTOINCREMENT,
               ip text NOT NULL, acl text NOT NULL, blocked boolean NOT NULL,host boolean
               NOT NULL)'''
    if not os.path.isfile(file_name):
        dir_path = os.path.dirname(os.path.realpath(__file__))
        conn = sqlite3.connect("{}/{}".format(dir_path, file_name))
        cursor = conn.cursor()
        cursor.execute(make_table)
        conn.commit()
    else:
        try:
            conn = sqlite3.connect(file_name)
            cursor = conn.cursor()
            cursor.execute(make_table)
            conn.commit()
        except Exception:
            print "Datatbase File is encrypted or is not a database"
            exit(1)
    return conn
 
 
def main():
    logging.basicConfig(level=logging.ERROR)
    my_logger = logging.getLogger(__file__)
    my_logger.info('Checking arguments')
    parser = argparse.ArgumentParser(description="Script to block IPs on AWS EC2 Network ACL")
    parser.add_argument('-a', '--acl', help='ACL ID')
    parser.add_argument('-j', '--jail', help='Fail2Ban Jail')
    parser.add_argument('-d', '--db', default='aws-nacl.db', help='Database')
    parser.add_argument('-b', '--block', metavar="IP", help='Block IP address')
    parser.add_argument('-u', '--unblock', metavar="IP", help='Unblock IP address')
    parser.add_argument('-g', '--get', action='store_true', help='Get ACL')
    parser.add_argument('-v', '--verbose', action='store_true', help='Verbose logging')
    args = parser.parse_args()
 
    ec2_resource = boto3.resource('ec2')
    pretty_printer = pprint.PrettyPrinter(indent=4)
 
    if args.verbose:
        my_logger.info('Setting logging to debug')
        my_logger.setLevel(logging.DEBUG)
 
    if (args.block and args.unblock):
        my_logger.error('Invalid arguments')
        parser.print_usage()
        exit(1)
 
    if args.acl:
        my_logger.info('Checking if valid AWS Network ACL')
        if not is_acl(args.acl):
            print('Invalid Network ACL ID')
            my_logger.error('Invalid Network ACL')
            exit(1)
    else:
        my_logger.info('Searching for current ACL ID')
        acl = get_acl_id()
        network_acl = ec2_resource.NetworkAcl(acl)
        my_logger.debug('Network ACL ID: {}'.format(network_acl))
 
    if args.get or (not args.block and not args.unblock):
        my_logger.info('Printing ACL')
        #pretty_printer.pprint(get_acl(acl)['NetworkAcls'][0]['Entries'])
        print_inbound_acl(acl)
        exit(0)
 
 
    my_logger.info('Configuring DB')
    conn = sqlite_connect(args.db)
    cursor = conn.cursor()
 
    if args.block:
        my_logger.info('Checking if valid IP')
        if not validate_ip(args.block):
            print "IP {} is invalid".format(args.ip)
            exit(1)
        my_logger.info('Searching DB for IP: {}'.format(args.block))
        cursor.execute('''select count (*) from blocks where ip=? and blocked=1''', (args.block,))
        if cursor.fetchone()[0] &gt; 0:
            print "IP {} already blocked".format(args.block)
            exit(0)
        my_logger.info('Checking AWS block count')
        cursor.execute('''select count (*) from blocks where blocked=1 and host =0''')
        block_count = cursor.fetchone()[0]
        my_logger.debug('Currently {} IPs blocked'.format(block_count))
        if block_count &lt;= MAX_BLOCKS:
            my_logger.debug('Current blocks less then Max: {}'.format(MAX_BLOCKS))
            my_logger.info('Adding block to the DB')
            cursor.execute('''insert into blocks (ip, acl, blocked,host)
                               values (?,?,?,?)''', (args.block, acl, 1, 0))
            conn.commit()
            my_logger.info('Caculating Rule number based on DB ID')
            cursor.execute('''select seq from sqlite_sequence where name="blocks"''')
            rule_num = cursor.fetchone()[0] % RULE_RANGE + RULE_BASE
            my_logger.info('Adding Network ACL')
            network_acl.create_entry(
                CidrBlock=args.block+'/32',
                DryRun=False,
                Egress=False,
                PortRange={
                    'From': 0,
                    'To': 65535
                },
                Protocol='-1',
                RuleAction='deny',
                RuleNumber=rule_num
            )
            if not check_block(args.block, acl):
               my_logger.error('Failed to block IP {} in AWS ACL'.format(args.block))
               cursor.execute('''UPDATE blocks SET blocked = 0 where ip=? and
                              blocked=1''', (args.block,))
               conn.commit()
        else:
            my_logger.debug('Max blocks on AWS Network ACL, checking for IPTables')
            if  args.jail:
                my_logger.info('Blocking IP {} in f2b-{}'.format(args.block,args.jail))
                iptables = "/sbin/iptables -w -I {} 1 -s {} -j REJECT".format(args.jail, args.block)
                print iptables
                subprocess.call(iptables, shell=True)
                cursor.execute('''insert into blocks (ip, acl, blocked,host)
                                  values (?,?,?,?)''', (args.block, '', 1, 1))
                conn.commit()
            else:
                my_logger.error('No IPtables Chain set, IP will not be blocked')
    if args.unblock:
        my_logger.info('Checking if valid IP')
        if not validate_ip(args.unblock):
            my_logger.error("IP {} is invalid".format(args.unblock))
            exit(1)
        my_logger.info('Checking for IP in the DB')
        test = 'select id, host from blocks where ip="{}" and blocked=1'.format(args.unblock)
        cursor.execute(test)
        results = cursor.fetchone()
        if results is not None:
            my_logger.info('Found IP, getting rule number from DB')
            if results[1] == 0:
                rule_num = results[0] % RULE_RANGE + RULE_BASE
                my_logger.debug('Rule number is {}'.format(rule_num))
                my_logger.info('Deleting rule from AWS Network ACL')
                response = network_acl.delete_entry(
                    DryRun=False,
                    Egress=False,
                    RuleNumber=rule_num
                )
                my_logger.info('Updating DB')
                cursor.execute('''UPDATE blocks SET blocked = 0 where ip=? and
                                   blocked=1''', (args.unblock,))
                conn.commit()
            else:
                if args.jail:
                    my_logger.info('Unblocking IP {} in f2b-{}'.format(args.unblock,args.jail))
                    iptables = 'iptables -w -D {} -s {} -j REJECT'.format(args.jail, args.unblock)
                    subprocess.call(iptables, shell=True)
                    cursor.execute('''UPDATE blocks SET blocked = 0 where ip=? and blocked=1''', (args.unblock,))
                    conn.commit()
        else:
            my_logger.error("IP {} not in blocks database".format(args.unblock))
            exit(1)
 
 
if __name__ == "__main__":
    main()</pre>
<p class="auto-cursor-target">4. Test the script by calling it</p>
<pre class="lang:sh decode:true">python aws_nacl.py -d aws-nacl.db -b 1.2.3.4 -v</pre>
<p class="auto-cursor-target">5. Verify that the above IP was added to the ACL</p>
<pre class="lang:sh decode:true ">python aws_nacl.py -g</pre>
<p class="auto-cursor-target">6. Remove the IP again</p>
<pre class="lang:sh decode:true ">python aws_nacl.py -d aws-nacl.db -u 1.2.3.4 -v</pre>
<p class="auto-cursor-target">7. Verify that the IP was removed again</p>
<pre class="lang:sh decode:true">python aws_nacl.py -g</pre>
<h1></h1>
<h1 id="PHC-Fail2BanwithAWSVPCACLs-Fail2Ban">Fail2Ban</h1>
<p>1. Install Fail2Ban itself</p>
<pre class="lang:sh decode:true">yum install fail2ban</pre>
<p class="auto-cursor-target">2. Place the following file under /etc/fail2ban/action.d/aws.conf</p>
<div class="code panel pdl conf-macro output-block" data-hasbody="true" data-macro-name="code" data-macro-id="546f63e6-c40c-46fc-aefa-ffe8445a881a">
<div class="codeHeader panelHeader pdl hide-border-bottom">
<pre class="minimize:true lang:default decode:true"># Fail2Ban configuration file
#
# Author: Cyril Jaquier
# Modified by Yaroslav Halchenko for multiport banning
# Modified by Ryan for AWS Network ACL block
#
 
[INCLUDES]
 
before = iptables-blocktype.conf
 
[Definition]
 
# Option:  actionstart
# Notes.:  command executed once at the start of Fail2Ban.
# Values:  CMD
#
actionstart = iptables -N fail2ban-&lt;name&gt;
              iptables -A fail2ban-&lt;name&gt; -j RETURN
              iptables -I &lt;chain&gt; -p &lt;protocol&gt; --dport &lt;port&gt; -j fail2ban-&lt;name&gt;
 
# Option:  actionstop
# Notes.:  command executed once at the end of Fail2Ban
# Values:  CMD
#
actionstop = iptables -D &lt;chain&gt; -p &lt;protocol&gt; --dport &lt;port&gt; -j fail2ban-&lt;name&gt;
             iptables -F fail2ban-&lt;name&gt;
             iptables -X fail2ban-&lt;name&gt;
 
# Option:  actioncheck
# Notes.:  command executed once before each actionban command
# Values:  CMD
#
actioncheck = iptables -n -L &lt;chain&gt; | grep -q 'fail2ban-&lt;name&gt;[ \t]'
 
# Option:  actionban
# Notes.:  command executed when banning an IP. Take care that the
#          command is executed with Fail2Ban user rights.
# Tags:    See jail.conf(5) man page
# Values:  CMD
#
actionban = python /opt/aws-nacl/aws_nacl.py -d /opt/aws-nacl/aws-nacl.db -v -b &lt;ip&gt; -j fail2ban-&lt;name&gt;
# Option:  actionunban
# Notes.:  command executed when unbanning an IP. Take care that the
#          command is executed with Fail2Ban user rights.
# Tags:    See jail.conf(5) man page
# Values:  CMD
#
actionunban = python /opt/aws-nacl/aws_nacl.py -d /opt/aws-nacl/aws-nacl.db -v -u &lt;ip&gt; -j fail2ban-&lt;name&gt;
 
[Init]
 
# Default name of the chain
#
name = default
 
# Option:  port
# Notes.:  specifies port to monitor
# Values:  [ NUM | STRING ]  Default:
#
port = ssh
 
# Option:  protocol
# Notes.:  internally used by config reader for interpolations.
# Values:  [ tcp | udp | icmp | all ] Default: tcp
#
protocol = tcp
 
# Option:  chain
# Notes    specifies the iptables chain to which the fail2ban rules should be
#          added
# Values:  STRING  Default: INPUT
chain = INPUT</pre>
<p>3. Modify /etc/fail2ban/fail2ban.conf and change the logfile location (it&#8217;s easier to have a separate log rather then searching through /var/log/messages)</p>
</div>
<div>
<pre class="lang:default decode:true">logtarget = /var/log/fail2ban.log</pre>
</div>
</div>
<p class="auto-cursor-target">4. Add a file /etc/fail2ban/jail.local with the following content. Modify the values at your own convenience</p>
<pre class="lang:default decode:true">[DEFAULT]
#Localhost and your office HQ range
ignoreip = 127.0.0.1/8 10.10.10.0/24

[ssh-iptables]
action = aws[name=SSH, port=ssh, protocol=tcp]

# "bantime" is the number of seconds that a host is banned.
bantime  = 3600

# "maxretry" is the number of failures before a host get banned.
maxretry = 2</pre>
<p class="auto-cursor-target">5. Check /etc/fail2ban/filter.d/sshd.conf that the correct matching patterns for the /var/log/secure logfile are present, so that it actually looks for the loglines that you want to be considered as malicious. On an Amazon Linux, I have the following in place</p>
<pre class="lang:default decode:true">failregex = ^%(__prefix_line)s(?:error: PAM: )?[aA]uthentication (?:failure|error) for .* from &lt;HOST&gt;( via \S+)?\s*$
            ^%(__prefix_line)s(?:error: PAM: )?User not known to the underlying authentication module for .* from &lt;HOST&gt;\s*$
            ^%(__prefix_line)sFailed \S+ for .* from &lt;HOST&gt;(?: port \d*)?(?: ssh\d*)?\s*$
            ^%(__prefix_line)sROOT LOGIN REFUSED.* FROM &lt;HOST&gt;\s*$
            ^%(__prefix_line)s[iI](?:llegal|nvalid) user .* from &lt;HOST&gt; .*$
            ^%(__prefix_line)sUser .+ from &lt;HOST&gt; not allowed because not listed in AllowUsers\s*$
            ^%(__prefix_line)sUser .+ from &lt;HOST&gt; not allowed because listed in DenyUsers\s*$
            ^%(__prefix_line)sUser .+ from &lt;HOST&gt; not allowed because not in any group\s*$
            ^%(__prefix_line)srefused connect from \S+ \(&lt;HOST&gt;\)\s*$
            ^%(__prefix_line)sUser .+ from &lt;HOST&gt; not allowed because a group is listed in DenyGroups\s*$
            ^%(__prefix_line)sUser .+ from &lt;HOST&gt; not allowed because none of user's groups are listed in AllowGroups\s*$
            ^%(__prefix_line)sReceived disconnect from &lt;HOST&gt; port \d*:11: Bye Bye \[preauth\]</pre>
<p class="auto-cursor-target">6. Add fail2ban to the startup list and start it</p>
<pre class="lang:sh decode:true ">chkconfig --add fail2ban
chkconfig fail2ban on
service fail2ban start</pre>
<h1></h1>
<h1 id="PHC-Fail2BanwithAWSVPCACLs-Lockedmyselfout">Locked myself out</h1>
<p>Things can always go wrong, but thanks to the recently released AWS feature called &#8216;SSM Session Manager&#8217; you can always get a console window on your instance to start troubleshooting. One thing to make sure is that your instance is running the latest version of the AWS SSM Agent. So it&#8217;s always a good idea to update it before closing your current SSH session:</p>
<pre class="lang:sh decode:true ">yum install https://s3.amazonaws.com/ec2-downloads-windows/SSMAgent/latest/linux_amd64/amazon-ssm-agent.rpm</pre>
<p>You also need to make sure that your instance is allowed to communicate with the AWS SSM service. Easiest way is to attach the &#8216;<span class="awsui-tooltip awsui-tooltip-no-slide awsui-tooltip-right awsui-tooltip-rounded awsui-tooltip-size-auto"><span class="ng-scope policy-name-with-icon">AmazonEC2RoleforSSM</span></span>&#8216; policy to your EC2 role.</p>
<h1></h1>
<h1 id="PHC-Fail2BanwithAWSVPCACLs-Credits">Credits</h1>
<p><a class="external-link" href="https://github.com/TheRemover/fail2ban-aws-nacl" rel="nofollow">https://github.com/TheRemover/fail2ban-aws-nacl</a></p>
<p><a class="external-link" href="https://techbytesecurity.com/2017/06/fail2ban-with-aws-network-acl" rel="nofollow">https://techbytesecurity.com/2017/06/fail2ban-with-aws-network-acl</a></p>
<p><a class="external-link" href="https://www.google.com" rel="nofollow">https://www.google.com</a></p>
<p>The post <a href="https://cloudar.be/awsblog/integrating-fail2ban-with-aws-network-acls/">Integrating Fail2Ban with AWS Network ACLs</a> appeared first on <a href="https://cloudar.be">Cloudar</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://cloudar.be/awsblog/integrating-fail2ban-with-aws-network-acls/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
			</item>
		<item>
		<title>Windows servers patching with AWS EC2 Systems Manager</title>
		<link>https://cloudar.be/awsblog/windows-servers-patching-with-aws-ec2-systems-manager/</link>
					<comments>https://cloudar.be/awsblog/windows-servers-patching-with-aws-ec2-systems-manager/#comments</comments>
		
		<dc:creator><![CDATA[Rutger Beyen]]></dc:creator>
		<pubDate>Mon, 29 May 2017 11:39:09 +0000</pubDate>
				<category><![CDATA[AWS Blog]]></category>
		<category><![CDATA[Amazon]]></category>
		<category><![CDATA[Amazon Web Services]]></category>
		<category><![CDATA[automation]]></category>
		<category><![CDATA[AWS]]></category>
		<category><![CDATA[EC2]]></category>
		<category><![CDATA[Run Command]]></category>
		<category><![CDATA[Systems Manager Services]]></category>
		<category><![CDATA[Windows Updates]]></category>
		<guid isPermaLink="false">https://cloudar.be/?p=3733</guid>

					<description><![CDATA[<p>&#160; Amazon EC2 Systems Manager is a collection of capabilities that helps you automate management tasks such as collecting system inventory, applying operating system patches, automating the creation of Amazon Machine Images (AMIs), and configuring operating systems and applications at scale. It is available at no cost to manage both your EC2 and on-premises resources! [&#8230;]</p>
<p>The post <a href="https://cloudar.be/awsblog/windows-servers-patching-with-aws-ec2-systems-manager/">Windows servers patching with AWS EC2 Systems Manager</a> appeared first on <a href="https://cloudar.be">Cloudar</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>&nbsp;</p>
<p>Amazon EC2 Systems Manager is a collection of capabilities that helps you automate management tasks such as collecting system inventory, applying operating system patches, automating the creation of Amazon Machine Images (AMIs), and configuring operating systems and applications at scale. It is available at no cost to manage both your EC2 and on-premises resources!</p>
<p>Amazon EC2 Systems Manager relies on the Amazon Simple Systems Management Service (SSM) agent being installed on the guests. The SSM agent is pre-installed on Windows Server 2016 instances or Windows Server 2003-2012 R2 instances created from AMI’s published after November 2016. You need at least SSM agent version 2.0.599.0 installed on the target EC2 instance.</p>
<p>In this article we will focus on using Systems Manager to apply Windows Updates to EC2 instances. Patch Management is always an operational pain point so its welcome that AWS offers a solution.</p>
<p>You start by creating groups of instances by applying a tag called &#8216;Patch Group&#8217;. Then you create a group of patches by forming a patch baseline containing and excluding the patches you require (or use the AWS default patch baseline). At last you create a maintenance window to have your patch baseline attached and applied to a patch group. The actual &#8216;Patch Now&#8217; run-command is nothing more than an API call, so there&#8217;s no obligation to use Maintenance Windows. Personally I&#8217;m a fan of Rundeck, so I&#8217;ll show you how to have the patches applied to the instances using both methods.</p>
<h2 id="WindowsServerspactchingwithAWSEC2SystemsManager-Configureyourinstances">Configure your instances</h2>
<p>The guest SSM agent setting inside with Windows OS requires permissions to connect to AWS EC2 Systems Manager. We grant these rights by creating an EC2 Service Role with the policy document ‘AmazonEC2RoleforSSM’ attached. Then you can attach this role to your instances. The instance also needs outbound internet connection to be able to connect to SSM. This can be either through an Internet Gateway or a NAT Gateway (or NAT Instance).</p>
<p>If you have this done right, your instance(s) should pop-up under &#8216;Managed Instances&#8217; in the EC2 console:</p>
<p><a href="https://cloudar.be/wp-content/uploads/2017/05/managed_instance-1.jpg"><img fetchpriority="high" decoding="async" class="alignnone wp-image-3735" src="https://cloudar.be/wp-content/uploads/2017/05/managed_instance-1.jpg" alt="" width="882" height="130" /></a></p>
<p>Take note of the SSM Agent Version. As said earlier it must be at least version 2.0.599.0. The Systems Manager Service also requires a &#8220;Patch Group&#8221;-tag on the EC2 instance. The key for a patch group tag must be <strong>Patch Group</strong>. Note that the key is case sensitive. The value can be anything you want to specify, but the key must be <strong>Patch Group.</strong></p>
<p><a href="https://cloudar.be/wp-content/uploads/2017/05/tags.jpg"><img decoding="async" class="alignnone wp-image-3736" src="https://cloudar.be/wp-content/uploads/2017/05/tags.jpg" alt="" width="796" height="148" /></a></p>
<p>If done correctly, your tag will be picked up by SSM. You can confirm this on the &#8216;Managed Instances&#8217; page:</p>
<p><a href="https://cloudar.be/wp-content/uploads/2017/05/ssm_status.jpg"><img decoding="async" class="alignnone wp-image-3737" src="https://cloudar.be/wp-content/uploads/2017/05/ssm_status.jpg" alt="" width="792" height="263" /></a></p>
<p>&nbsp;</p>
<h2 id="WindowsServerspactchingwithAWSEC2SystemsManager-PatchBaselines">Patch Baselines</h2>
<p>AWS provides a default Patch Baseline called &#8216;AWS-DefaultPatchBaseline&#8217;. It auto-approves all critical and security updates with a &#8216;critical&#8217; or &#8216;important&#8217; classification seven days after they have been released by Microsoft. If you&#8217;re happy with that you can use this baseline. If you&#8217;re not, you can simply create your own according to your requirements: set approval for specific products and patch classifications, exclude a specific KB etc</p>
<p><a href="https://cloudar.be/wp-content/uploads/2017/05/baseline.png"><img loading="lazy" decoding="async" class="alignnone wp-image-3738" src="https://cloudar.be/wp-content/uploads/2017/05/baseline.png" alt="" width="704" height="396" /></a></p>
<p>Once your happy with your baseline, you can hit &#8216;Create&#8217;. Now assign it to one or more Patch Groups (or make it the default baseline and throw away the AWS one). Hit the &#8216;actions&#8217; menu and chose &#8216;Modify Patch Groups&#8217;</p>
<p><a href="https://cloudar.be/wp-content/uploads/2017/05/patchbaseline.jpg"><img loading="lazy" decoding="async" class="alignnone wp-image-3739" src="https://cloudar.be/wp-content/uploads/2017/05/patchbaseline.jpg" alt="" width="463" height="152" /></a></p>
<p>Type the names of the Patch Groups you defined when tagging your instances</p>
<p><a href="https://cloudar.be/wp-content/uploads/2017/05/modifyPatchGroup.jpg"><img loading="lazy" decoding="async" class="alignnone wp-image-3740" src="https://cloudar.be/wp-content/uploads/2017/05/modifyPatchGroup.jpg" alt="" width="486" height="254" /></a></p>
<p>Your baseline is now attached to the specified patch groups. You can now start evaluating your instances against the baseline, and update them accordingly.</p>
<h2 id="WindowsServerspactchingwithAWSEC2SystemsManager-Patching">Patching</h2>
<p>Applying the patch baseline to a specific instance or to a patch group is nothing more than executing an AWS SSM run command. You can schedule this run command through AWS SSM &#8216;Maintenance Windows&#8217;, a cron job on a server (like Rundeck) or manual through the AWS Console.</p>
<p>Let&#8217;s first check everything manually. In the AWS EC2 console, go to &#8216;Run Commands&#8217; and create a new Run Command. Select the &#8216;AWS-ApplyPatchBaseline&#8217; command document and pick an instance run this on. For the &#8216;operation&#8217;, choose &#8216;Scan&#8217;. This will evaluate the instance against the baseline without installing anything yet.</p>
<p><a href="https://cloudar.be/wp-content/uploads/2017/05/ApplyPB.png"><img loading="lazy" decoding="async" class="alignnone wp-image-3741" src="https://cloudar.be/wp-content/uploads/2017/05/ApplyPB.png" alt="" width="609" height="381" /></a></p>
<p>Once the run command finishes, you can go back to the &#8216;Managed Instances&#8217; page. Highlight the instance(s) on which the run command was executed and click on the &#8216;Patch&#8217; tab. Here you can see the result of the scan:</p>
<p><a href="https://cloudar.be/wp-content/uploads/2017/05/patch_status.jpg"><img loading="lazy" decoding="async" class="alignnone wp-image-3742" src="https://cloudar.be/wp-content/uploads/2017/05/patch_status.jpg" alt="" width="719" height="212" /></a></p>
<p>To actually install the missing updates, execute the same run command document, but now with the &#8216;Install&#8217; operation. This will install the missing KBs to the instances and reboot them if needed.</p>
<p>Or execute the following aws cli command to accomplish the same:</p>
<pre class="lang:sh decode:true">aws ssm send-command --targets "Key=tag:Patch Group,Values=&lt;PatchGroupName&gt;" --document-name "AWS-ApplyPatchBaseline" --comment "Install|Check Windows Updates" --parameters Operation="&lt;Install|Scan&gt;"</pre>
<h2>Maintenance Windows</h2>
<p>In stead of manually starting a run command or cron job, we can also use the AWS provided Maintenance Windows feature. Systems Manager Maintenance Windows let you define a schedule for when to perform actions on your instances such as patching the operating system. Each Maintenance Window has a schedule, a duration, a set of registered targets, and a set of registered tasks.</p>
<p>Before actually creating a Maintenance Window, we must configure a Maintenance Window role. We need this so Systems Manager can execute tasks in Maintenance Windows on our behalf. So we go to the IAM page and create a new role. We pick an &#8220;EC2 service role&#8221; type and make sure to attach the &#8220;AmazonSSMMaintenanceWindowRole&#8221; policy to it. Once the role is created, we must modify it. Click &#8220;edit Trust Relationships&#8221;. Add a comma after &#8220;ec2.amazonaws.com&#8221;<b>,</b> and then add &#8220;Service&#8221;: &#8220;ssm.amazonaws.com&#8221; to the existing policy:</p>
<pre class="lang:default decode:true">{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Service": "ec2.amazonaws.com",
        "Service": "ssm.amazonaws.com"
      },
      "Action": "sts:AssumeRole"
    }
  ]
}</pre>
<p>Back to SSM now to actually create the Maintenance Window. Give it a useful name and specify your preferred schedule. I&#8217;m setting &#8216;every 30 minutes&#8217; just for demonstration purposes, but in a real setup you would most probably choose something like &#8216;Every  Sunday&#8217;. You can also configure your own Cron expression.</p>
<p><a href="https://cloudar.be/wp-content/uploads/2017/05/createMX.jpg"><img loading="lazy" decoding="async" class="alignnone wp-image-3744" src="https://cloudar.be/wp-content/uploads/2017/05/createMX.jpg" alt="" width="490" height="415" /></a></p>
<p>This leaves us now with an empty Maintenance Window: there are no tasks nor targets associated yet.</p>
<p>To assign targets to the Maintenance Window, click on the &#8220;Register new targets&#8221; button on the &#8220;Targets&#8221; tab. We dynamically select the targets by using the &#8220;Patch Group&#8221; tag.</p>
<p><a href="https://cloudar.be/wp-content/uploads/2017/05/register_target.jpg"><img loading="lazy" decoding="async" class="alignnone wp-image-3745" src="https://cloudar.be/wp-content/uploads/2017/05/register_target.jpg" alt="" width="615" height="281" /></a></p>
<p>We will now have an ID linked to our &#8220;dev&#8221; Patch Group. This &#8220;Window Target ID&#8221; is used in the next step.</p>
<p><a href="https://cloudar.be/wp-content/uploads/2017/05/targets.jpg"><img loading="lazy" decoding="async" class="alignnone wp-image-3747" src="https://cloudar.be/wp-content/uploads/2017/05/targets.jpg" alt="" width="481" height="183" /></a></p>
<p>From the &#8220;tasks&#8221; tab of the Maintenance Window, click on &#8220;Schedule new task&#8221;. Pick the &#8220;AWS-ApplyPatchBaseline&#8221; document. Under &#8220;Registered Targets&#8221;, select the correct Window Target ID. For the operation, select &#8220;Install&#8221;. For the &#8220;Role&#8221;, select the IAM role with the AmazonSSMMaintenanceWindowRole attached to it (the one we created earlier). Set your preferred concurrency level and register the task by clicking on the blue button. The end result should look like this:</p>
<p><a href="https://cloudar.be/wp-content/uploads/2017/05/task.jpg"><img loading="lazy" decoding="async" class="alignnone wp-image-3748" src="https://cloudar.be/wp-content/uploads/2017/05/task.jpg" alt="" width="636" height="539" /></a></p>
<p>Now we have to wait for the schedule of the Maintenance Window. In this example we specified &#8216;every 30 minutes&#8217; as a schedule, so the waiting shouldn&#8217;t take too long. Under the &#8216;History&#8217; tab of the Maintenance Window you can follow all actions. The Maintenance Window will simply launch a Run Command, so you could go to that console screen too. If you enabled logging to S3, you could find the output of the Run Command over there. If not, you can view a (truncated) output via the Run Command itself:</p>
<p><a href="https://cloudar.be/wp-content/uploads/2017/05/output.jpg"><img loading="lazy" decoding="async" class="alignnone wp-image-3750" src="https://cloudar.be/wp-content/uploads/2017/05/output.jpg" alt="" width="692" height="329" /></a></p>
<pre class="lang:default decode:true">Patch Summary for i-07ca5621af38f256d
PatchGroup          : dev
BaselineId          : pb-06101e06cf8506be6
SnapshotId          : 317f2b72-2612-4740-95af-c7b3d8fb6d1e
OwnerInformation    : 
OperationType       : Install
OperationStartTime  : 2017-05-29T11:00:14.0000000Z
OperationEndTime    : 2017-05-29T11:03:18.7164313Z
InstalledCount      : 1
InstalledOtherCount : 6
FailedCount         : 0
MissingCount        : 0
NotApplicableCount  : 3

EC2AMAZ-EA5SH8I - PatchBaselineOperations Installation Results - 2017-05-29T11:03:19.537

KbArticleId Installed   Message
----------- ----------- -----------
KB890830    Yes         Success</pre>
<p>If we now go back to the &#8220;Managed Instances&#8221; page and look at the &#8220;Patch&#8221; tab of our test instance, we will see it is not missing any updates anymore!</p>
<p><a href="https://cloudar.be/wp-content/uploads/2017/05/final_status.jpg"><img loading="lazy" decoding="async" class="alignnone wp-image-3751" src="https://cloudar.be/wp-content/uploads/2017/05/final_status.jpg" alt="" width="847" height="264" /></a></p>
<p>&nbsp;</p>
<p>Success! Another <a href="https://cloudar.be/wp-content/uploads/2017/05/images.jpg"><img loading="lazy" decoding="async" class="wp-image-3752 alignnone" src="https://cloudar.be/wp-content/uploads/2017/05/images.jpg" alt="" width="26" height="26" /></a> on the Automation checklist!</p>
<p>&nbsp;</p>
<p>Rutger</p>
<p>The post <a href="https://cloudar.be/awsblog/windows-servers-patching-with-aws-ec2-systems-manager/">Windows servers patching with AWS EC2 Systems Manager</a> appeared first on <a href="https://cloudar.be">Cloudar</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://cloudar.be/awsblog/windows-servers-patching-with-aws-ec2-systems-manager/feed/</wfw:commentRss>
			<slash:comments>6</slash:comments>
		
		
			</item>
		<item>
		<title>Multicast on AWS</title>
		<link>https://cloudar.be/awsblog/multicast-on-aws/</link>
					<comments>https://cloudar.be/awsblog/multicast-on-aws/#comments</comments>
		
		<dc:creator><![CDATA[Senne Vaeyens]]></dc:creator>
		<pubDate>Fri, 18 Jul 2014 20:46:09 +0000</pubDate>
				<category><![CDATA[AWS Blog]]></category>
		<category><![CDATA[Amazon]]></category>
		<category><![CDATA[AWS]]></category>
		<category><![CDATA[EC2]]></category>
		<category><![CDATA[intershop]]></category>
		<category><![CDATA[multicast]]></category>
		<category><![CDATA[n2n]]></category>
		<guid isPermaLink="false">https://cloudar.be/?p=323</guid>

					<description><![CDATA[<p>Recently, for an Intershop on Amazon Web Services Proof of Concept, a requirement was to enable multicast traffic between two EC2 instances, each running in another availability zone. As you might know, multicast traffic is natively not supported on AWS VPC, not in an availability zone nor between availability zones. This article explains how to [&#8230;]</p>
<p>The post <a href="https://cloudar.be/awsblog/multicast-on-aws/">Multicast on AWS</a> appeared first on <a href="https://cloudar.be">Cloudar</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p></br><br />
Recently, for an <a href="http://www.intershop.com/" target="_blank" rel="noopener noreferrer">Intershop</a> on Amazon Web Services Proof of Concept, a requirement was to enable multicast traffic between two EC2 instances, each running in another availability zone. As you might know, <a href="http://aws.amazon.com/vpc/faqs/" target="_blank" rel="noopener noreferrer">multicast traffic is natively not supported </a> on AWS VPC, not in an availability zone nor between availability zones.</p>
<p>This article explains how to enable multicast traffic between two (or more) hosts using an <a href="http://www.ntop.org/products/n2n/" target="_blank" rel="noopener noreferrer">n2n</a> L2 tunnel (we use CentOS 6.5).</p>
<p>&nbsp;</p>
<pre>#First; install compile tools &amp; s3cmd
yum -y install svn make gcc s3cmd

#Download the code
svn co https://svn.ntop.org/svn/ntop/trunk/n2n

#Disable encryption and compression before compiling the binaries; this should improve performance
cd n2n/n2n_v2
sed -i "s/#N2N_OPTION_AES=no/N2N_OPTION_AES=no/g" Makefile
sed -i "s/#define N2N_COMPRESSION_ENABLED 1/#define N2N_COMPRESSION_ENABLED 0/g" n2n.h
make
</pre>
<p>&nbsp;</p>
<p>The make process should now have created two binaries:</p>
<ul>
<li>supernode -&gt; to be run on the supernode, used for connection setup and VPN tunnel registration</li>
<li>edge -&gt; to be run on the nodes that will participate in multicast traffic</li>
</ul>
<p>&nbsp;</p>
<pre>#Install the supernode binary on this host
cp ./supernode /usr/bin/

#store binaries in s3

s3cmd put supernode s3://bucketname/files/supernode
s3cmd put edge s3://bucketname/files/edge

# on the edge servers, install the edge binary

s3cmd get s3://bucketname/files/edge /usr/bin/edge
chmod +x /usr/bin/edge
</pre>
<p>&nbsp;</p>
<p>On the supernode, start the supernode process and add it to rc.local so it starts automatically when we start the instance. The deamon is listening on UDP port 1200, so don&#8217;t forget to create an AWS Security Group that allows UDP traffic on this port between all nodes that participate in the n2n tunnel (also include the supernode).</p>
<p>&nbsp;</p>
<pre>#start the supernode and automatically start it on reboot 

supernode -l 1200
echo "supernode -l 1200" &gt;&gt; /etc/rc.local
</pre>
<p>&nbsp;</p>
<p>We then start the edge process on the multicast-enabled nodes. Please note that 192.168.1.1 and 192.168.1.2 are the tunnel&#8217;s endpoint addresses which will be associated with the edge0 interface created by the edge process. n2na1 is the hostname of the supernode, the -E parameter allows multicast over the tunnel:</p>
<p>&nbsp;</p>
<pre>#App server 1

edge -l n2na1:1200 -c Intershop -a 192.168.1.1 -E
echo "edge -l n2na1:1200 -c Intershop -a 192.168.1.1" &gt;&gt; /etc/rc.local

#App server 2

edge -l n2na1:1200 -c Intershop -a 192.168.1.2 -E
echo "edge -l n2na1:1200 -c Intershop -a 192.168.1.2" &gt;&gt; /etc/rc.local
</pre>
<p>&nbsp;</p>
<p>We can verify if edge was started correctly by checking if the edge0 interface was created:</p>
<p>&nbsp;</p>
<pre>root@Appa1 $ ifconfig edge0
edge0     Link encap:Ethernet  HWaddr c7:5a:4b:ba:34:21
          inet addr:192.168.1.1  Bcast:192.168.1.255  Mask:255.255.255.0
          UP BROADCAST RUNNING MULTICAST  MTU:1400  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:5 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:500
          RX bytes:0 (0.0 B)  TX bytes:816 (816.0 B)
</pre>
<p>&nbsp;</p>
<p>At this stage, multicast traffic between both EC2 instance over the edge0 interface should be possible. To make sure that all multicast traffic chooses the edge0 interface, we set up a static route:</p>
<p>&nbsp;</p>
<pre>#route multicast trough n2n, but during startup, wait 10 secs for the edge0 interface to become available 
route add -net 224.0.0.0 netmask 240.0.0.0 dev edge0
echo "sleep 10" &gt;&gt; /etc/rc.local
echo "route add -net 224.0.0.0 netmask 240.0.0.0 dev edge0" &gt;&gt; /etc/rc.local
</pre>
<p>&nbsp;</p>
<p>Tx to <a href="https://www.buckhill.co.uk/blog/how-to-enable-broadcast-and-multicast-on-amazon-aws-ec2/2#.U8tL9I2Symd" target="_blank" rel="noopener noreferrer">buckhill</a> for their post on n2n<br />
</br></br></br></p>
<p>The post <a href="https://cloudar.be/awsblog/multicast-on-aws/">Multicast on AWS</a> appeared first on <a href="https://cloudar.be">Cloudar</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://cloudar.be/awsblog/multicast-on-aws/feed/</wfw:commentRss>
			<slash:comments>6</slash:comments>
		
		
			</item>
	</channel>
</rss>
