splunk aws add-on inputs

The Splunk Add-on for AWS is an addon supporting data collection from AWS services. At the time of writing, it can seamlessly collect AWS config, AWS config rules, AWS Cloudtrail, CloudWatch, Cloudwatch logs and AWS inspector, Kinesis, S3 via SQS and billing data.

This article touches the method of collecting data using IAM roles. This involves setting up an IAM role for EC2, assigning it to the Splunk instance where the AWS Add-on is installed, then configure that role for collection jobs.

To collect data from multiple accounts, a role is needed in each AWS account with a policy that allows reading from the services that need to be collected, which will be assumed by the role asigned to the EC2 running Splunk Add-on. Within accounts, I called the role Splunk_Role.

The Addon relies on configurations that tell it what inputs to collect and where from. Splunk Add-on for AWS provides two methods of collecting inputs: using the UI and using configuration files.

While the UI may be a practical option when collecting inputs from one AWS account, it can become painful to click through the UI to setup collection of multiple inputs from hundreds of AWS accounts.

Fortunately, inputs can also be configured using configuration files. These files are stored in folder $SPLUNK_HOME/etc/apps/Splunk_TA_aws/local/
Some of the inputs are concatenated in inputs.conf, other have individual configuration files.

Ansible playbook

Ansible uses the concept of roles. A role is a mechanism of breaking a playbook into multiple files, simplifying complex playbooks and making them easier to reuse.

For this example, we will create an individual role for each type of Splunk AWS Add-on input and have the execution of the playbook produce resulting configuration files locally in folder output/. All the roles will be then called from the main playbook which will also assemble inputs according to the expected Splunk structure.

Ansible Role Config file Purpose
splunk_ta_aws_iam_roles   splunk_ta_aws_iam_roles.conf Specifies ARNs of the roles assumed in each AWS account
aws_description   aws_description_tasks.conf Configuration file for collection of AWS metadata
cloudwatch inputs.conf Configuration file for collection of CloudWatch Metrics

Structure of the playbook

├── group_vars
│   └── all
├── output
│   ├── aws_description_tasks.conf
│   ├── inputs.conf
│   ├── splunk_ta_aws_iam_roles.conf
│   └── tmp
│       └── cloudwatch.conf
├── roles
│   ├── aws_description
│   │   ├── files
│   │   ├── tasks
│   │   │   └── main.yml
│   │   ├── templates
│   │   │   └── aws_description_tasks.conf.j2
│   │   └── vars
│   │       └── main.yml
│   ├── cloudwatch
│   │   ├── files
│   │   ├── tasks
│   │   │   └── main.yml
│   │   ├── templates
│   │   │   └── cloudwatch.conf.j2
│   │   └── vars
│   │       └── main.yml
│   └── splunk_ta_aws_iam_roles
│       ├── tasks
│       │   └── main.yml
│       ├── templates
│       │   └── splunk_ta_aws_iam_roles.conf.j2
│       └── vars
│           └── main.yml
└── site.yml

To create .config files, the playbook uses JINJA2 language which is a templating language for python. It allows us to create consistent configuration files, iterating through a set of variables. 


The playbook uses local and global variables. Global variables are defined in group_vars/all and are used by all roles

  - accountid: 321321321321
    accountname: zebras-prod
  - accountid: 654654654654
    accountname: zebras-acc
  - accountid: 987987987987
    accountname: zebras-test

Role splunk_ta_aws_iam_roles

An entry is being created for each of the roles to be assumed within AWS Accounts. The role name in accounts is always Splunk_Role. This role must be deployed in the accounts beforehand.
The name of the IAM role to be assumed is for simplicity, the account number

{% for item in accounts %}
[{{ item.accountid }}]
arn = arn:aws:iam::{{item.accountid}}:role/Splunk_Role
{% endfor %}

Role aws_description

This JINJA template uses global variables found in group_vars, specified iterating with_items and variables local to the role, specified in vars/main.yml

Role definition

  - name: Generate aws metadata file (aws_description_tasks.yml)
      src: aws_description_tasks.conf.j2
      dest: output/aws_description_tasks.conf
      remote_src: true
    with_items: "{{ accounts }}"

JINJA2 template

{% for item in accounts %}

[{{ item.accountid }}-{{ item.accountname }}_description]
account = {{ account }}
apis = ec2_volumes/3600, ec2_instances/3600, ec2_reserved_instances/3600, ebs_snapshots/3600, classic_load_balancers/3600, application_load_balancers/3600, vpcs/3600, vpc_n
etwork_acls/3600, cloudfront_distributions/3600, vpc_subnets/3600, rds_instances/3600, ec2_key_pairs/3600, ec2_security_groups/3600, ec2_images/3600, ec2_addresses/3600, la
mbda_functions/3600, s3_buckets/3600, iam_users/3600
index = {{ item.accountid }}-{{ item.accountname }}
regions = {{ regions }}
sourcetype = aws:description
aws_iam_role = {{ item.accountid }}

{% endfor %}

Role cloudwatch

At the end of the definition for CloudWatch inputs splunk appends a UUID
In order to generate a UUID with Ansible, we're harnessing filter to_uuid

[aws_cloudwatch://{{ item.accountid }}-{{ item.accountname }}_cloudwatch_{{ 9999999999999999999999 | random | to_uuid }}_]
aws_account = {{ account }}
aws_iam_role = {{ item.accountid }}
aws_region = {{ regions }}
index = {{ item.accountid }}-{{ item.accountname }}
metric_dimensions = [{"ServiceName":[".*"],"Currency":[".*"]}]
metric_names = ".*"
metric_namespace = AWS/Billing
period = 300
polling_interval = 3600
sourcetype = aws:cloudwatch
statistics = ["Average","Sum","SampleCount","Maximum","Minimum"]
use_metric_format = false


Run the playbook and see the results in folder output/

ansible-playbook site.yml

Browse the code of this Ansible playbook on GitHub https://github.com/monids/splunk-aws-addon-ansible


Notices All product names, logos, and brands are property of their respective owners. Splunk is a trademark of Splunk Inc. or its subsidiaries, registered or used in many jurisdictions worldwide.