<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: zoltan</title>
    <description>The latest articles on DEV Community by zoltan (@zoltan_tech).</description>
    <link>https://dev.to/zoltan_tech</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1133221%2F69b4f794-06f8-4af8-a89e-973782e62e9d.png</url>
      <title>DEV Community: zoltan</title>
      <link>https://dev.to/zoltan_tech</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/zoltan_tech"/>
    <language>en</language>
    <item>
      <title>Automated threat detection on Amazon EKS using Terraform and GuardDuty</title>
      <dc:creator>zoltan</dc:creator>
      <pubDate>Wed, 27 Sep 2023 06:22:30 +0000</pubDate>
      <link>https://dev.to/zoltan_tech/automated-threat-detection-on-amazon-eks-using-terraform-and-guardduty-313c</link>
      <guid>https://dev.to/zoltan_tech/automated-threat-detection-on-amazon-eks-using-terraform-and-guardduty-313c</guid>
      <description>&lt;p&gt;Effective monitoring of Kubernetes audit logs offers several benefits. First and foremost, it helps in identifying unauthorized access attempts, unusual or suspicious activities, and potential security breaches. This enables administrators to take immediate action to mitigate risks and prevent further damage.&lt;/p&gt;

&lt;p&gt;However, having logs just for the sake of it is a waste of money and effort if no one is checking them. This is where Amazon GuardDuty can easily help with its &lt;a href="https://docs.aws.amazon.com/guardduty/latest/ug/guardduty-eks-audit-log-monitoring.html"&gt;new feature&lt;/a&gt; that offers automated monitoring for these the audit logs.&lt;/p&gt;

&lt;h2&gt;
  
  
   Example findings
&lt;/h2&gt;

&lt;p&gt;Couple of examples that it can spot for you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;CredentialAccess:Kubernetes/MaliciousIPCaller&lt;/code&gt; - An API commonly used to access credentials or secrets in a Kubernetes cluster was invoked from a known malicious IP address.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;PrivilegeEscalation:Kubernetes/PrivilegedContainer&lt;/code&gt; - A privileged container with root level access was launched on your Kubernetes cluster.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Policy:Kubernetes/ExposedDashboard&lt;/code&gt; - The dashboard for a Kubernetes cluster was exposed to the internet&lt;/li&gt;
&lt;li&gt;Or my personal favourite: &lt;code&gt;Policy:Kubernetes/AnonymousAccessGranted&lt;/code&gt; - The system:anonymous user was granted API permission on a Kubernetes cluster.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;&lt;a href="https://docs.aws.amazon.com/guardduty/latest/ug/guardduty_finding-types-kubernetes.html"&gt;More can be found here.&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;To use this new feature, there are 2 things you need to do:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Enable audit logs on your EKS cluster (if you haven't done  already)&lt;/li&gt;
&lt;li&gt;Setup EKS Audit log monitoring in GuardDuty&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Enable audit logs on your EKS cluster using Terraform
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Using aws_eks_cluster resource
&lt;/h3&gt;

&lt;p&gt;If you are using the &lt;a href="https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/eks_cluster"&gt;aws_eks_cluster&lt;/a&gt; resource, then you basically need to add a single line to it to enable Audit Logging.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight terraform"&gt;&lt;code&gt;&lt;span class="k"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_eks_cluster"&lt;/span&gt; &lt;span class="s2"&gt;"example"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;# ... other configurations ...&lt;/span&gt;

  &lt;span class="nx"&gt;enabled_cluster_log_types&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"audit"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="c1"&gt;# Additional types: api, authenticator, controllerManager, scheduler&lt;/span&gt;

  &lt;span class="c1"&gt;# ... other configurations ...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Using AWS's EKS Terraform module
&lt;/h3&gt;

&lt;p&gt;If you are using the official &lt;a href="https://registry.terraform.io/modules/terraform-aws-modules/eks/aws/latest?tab=inputs"&gt;EKS Terraform module&lt;/a&gt;, then you will need to make sure that &lt;code&gt;audit&lt;/code&gt; is added to the &lt;code&gt;cluster_enabled_log_types&lt;/code&gt; input parameter as below. &lt;em&gt;(By default, it is already configured)&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight terraform"&gt;&lt;code&gt;&lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="s2"&gt;"eks"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;source&lt;/span&gt;  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"terraform-aws-modules/eks/aws"&lt;/span&gt;
  &lt;span class="nx"&gt;version&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"~&amp;gt; 19.0"&lt;/span&gt;
  &lt;span class="c1"&gt;# ... other configurations ...&lt;/span&gt;
  &lt;span class="nx"&gt;cluster_enabled_log_types&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"audit"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="c1"&gt;# ... other configurations ...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
   Setup GuardDuty using Terraform for EKS Audit log
&lt;/h2&gt;

&lt;p&gt;With the official &lt;a href="https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/guardduty_detector"&gt;aws_guardduty_detector resource&lt;/a&gt; this is fairly simple and it only takes a few lines.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight terraform"&gt;&lt;code&gt;&lt;span class="k"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_guardduty_detector"&lt;/span&gt; &lt;span class="s2"&gt;"example"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;enable&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;

  &lt;span class="nx"&gt;datasources&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;# ... other configurations ...&lt;/span&gt;
    &lt;span class="nx"&gt;kubernetes&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;audit_logs&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;enable&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="c1"&gt;# ... other configurations ...&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once you set it up, you should start receiving alerts from GuardDuty when it detects suspicious activities. For the fill list of findings, &lt;a href="https://docs.aws.amazon.com/guardduty/latest/ug/guardduty_finding-types-kubernetes.html"&gt;check out the official documentation&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>aws</category>
      <category>security</category>
      <category>devops</category>
      <category>infrastructureascode</category>
    </item>
    <item>
      <title>Dynamic number of SNS subscribers using AWS CloudFormation ForEach</title>
      <dc:creator>zoltan</dc:creator>
      <pubDate>Sat, 05 Aug 2023 19:15:28 +0000</pubDate>
      <link>https://dev.to/zoltan_tech/dynamic-number-of-sns-subscribers-using-aws-cloudformation-foreach-556h</link>
      <guid>https://dev.to/zoltan_tech/dynamic-number-of-sns-subscribers-using-aws-cloudformation-foreach-556h</guid>
      <description>&lt;p&gt;CloudFormation is an AWSome service that empowers users to define and provision AWS resources using simple JSON or &lt;strong&gt;YAML&lt;/strong&gt; templates. It allows for the automated deployment and management of complex cloud infrastructures, ensuring consistency and reducing manual errors. With CloudFormation, you can describe cloud-based applications and services in a declarative way, making it easier to update, delete, and recreate resources as needed. By providing infrastructure as code capabilities, CloudFormation streamlines the process of building and maintaining AWS environments, promoting scalability and reliability in cloud deployments.&lt;/p&gt;

&lt;p&gt;The problem arises when you start using it at scale. One of the most common use-cases for CloudFormation is to &lt;strong&gt;simply deploy some basic templates/resources&lt;/strong&gt;. While Terraform is well-suited for complex projects, CloudFormation, in my opinion, is superior when you only need to accomplish a simple task. For instance, I often need to set up some basic alerting in customer environments, such as budget alerts or basic CloudWatch alarms.&lt;/p&gt;

&lt;p&gt;One of the most frustrating issues I have encountered is that it became &lt;strong&gt;increasingly difficult to create an SNS topic with a dynamic number of subscribers&lt;/strong&gt; without modifying the actual CloudFormation template (thus avoiding the addition of extra Parameters, for example). The only way to achieve this was via &lt;a href="https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/template-custom-resources.html"&gt;Custom Resources&lt;/a&gt;. While this approach works fine, it necessitates the creation of additional Lambda functions as part of your template, which requires IAM roles and code maintenance over time, even when all you needed was to add another email address as a subscriber to your SNS topic.&lt;/p&gt;

&lt;p&gt;The solution below is not flawless, and it &lt;strong&gt;introduces a different bottleneck&lt;/strong&gt; that can complicate your template, but it simplifies setups like these. So, let's explore the full solution first, and then we can delve into the details of why certain parts are as they are.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;AWSTemplateFormatVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;2010-09-09&lt;/span&gt;
&lt;span class="na"&gt;Transform&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; 
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;AWS::LanguageExtensions'&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;AWS::Serverless-2016-10-31'&lt;/span&gt;
&lt;span class="na"&gt;Description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Sample Cloudformation file for SNS subscriptions&lt;/span&gt;
&lt;span class="na"&gt;Parameters&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;Subscribers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;String&lt;/span&gt;
    &lt;span class="na"&gt;Description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Comma separated list of subscribers&lt;/span&gt;
    &lt;span class="na"&gt;Default&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;
  &lt;span class="na"&gt;SubscriberIndexes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;String&lt;/span&gt;
    &lt;span class="na"&gt;Description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
      &lt;span class="s"&gt;Comma separated list of indexes.&lt;/span&gt;
      &lt;span class="s"&gt;Should start from 0 and should be in sequence upto the number of subscribers.&lt;/span&gt;

      &lt;span class="s"&gt;It is used as a helper to create unique logical ids for subscriptions.&lt;/span&gt;
    &lt;span class="na"&gt;Default&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;
&lt;span class="na"&gt;Resources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;SampleTopic&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;AWS::SNS::Topic&lt;/span&gt;
    &lt;span class="na"&gt;Properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;DisplayName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Sample Topic&lt;/span&gt;
      &lt;span class="na"&gt;TopicName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;sample-topic&lt;/span&gt;
  &lt;span class="s"&gt;Fn::ForEach::Subscriptions:&lt;/span&gt;
      &lt;span class="s"&gt;- EmailIndex&lt;/span&gt;
      &lt;span class="s"&gt;- !Split [',', !Ref SubscriberIndexes]&lt;/span&gt;
      &lt;span class="s"&gt;- SampleTopicSub${EmailIndex}&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;AWS::SNS::Subscription&lt;/span&gt;
          &lt;span class="na"&gt;Properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;Endpoint&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;!Select&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;!Sub&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;${EmailIndex}"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;!Split&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;,'&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;!Ref&lt;/span&gt; &lt;span class="nv"&gt;Subscribers&lt;/span&gt;&lt;span class="pi"&gt;]]&lt;/span&gt;
            &lt;span class="na"&gt;Protocol&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;email&lt;/span&gt;
            &lt;span class="na"&gt;TopicArn&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;!Ref&lt;/span&gt; &lt;span class="s"&gt;SampleTopic&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The first thing you notice, is that there are 2 parameters.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;code&gt;Subscribers&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;SubscriberIndexes&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The param &lt;code&gt;Subscribers&lt;/code&gt; speaks for itself. It is what we need after all. A comma (&lt;code&gt;,&lt;/code&gt;) separated list of email addresses that should be subscribed to our new SNS topic.&lt;/p&gt;

&lt;p&gt;So let's look at what &lt;code&gt;SubscriberIndexes&lt;/code&gt; is for. It should be a list of "indexes" that we will need to use unfortunately, to get around some of the limitations of the &lt;a href="https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference-foreach.html"&gt;&lt;code&gt;Fn::ForEach&lt;/code&gt;&lt;/a&gt; function.&lt;/p&gt;

&lt;p&gt;If you look at &lt;a href="https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference-foreach.html"&gt;the documentation&lt;/a&gt; for it, you may notice that we need to set the key dynamically. Unfortunately, this key has some limitations as it can only contain alphanumeric characters. As you probably correctly recall, an  at sign (&lt;code&gt;@&lt;/code&gt;) or the dot (&lt;code&gt;.&lt;/code&gt;) in the email does not count as "alphanumeric". So we need a way to generate a new index.&lt;/p&gt;

&lt;p&gt;To get around this problem, we will actually build our loop on a new parameter called &lt;code&gt;SubscriberIndexes&lt;/code&gt; instead of the original list of emails.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="nn"&gt;...&lt;/span&gt;
  &lt;span class="s"&gt;Fn::ForEach::Subscriptions:&lt;/span&gt;
      &lt;span class="s"&gt;- EmailIndex&lt;/span&gt;
      &lt;span class="s"&gt;- !Split [',', !Ref SubscriberIndexes]&lt;/span&gt;
      &lt;span class="s"&gt;- SampleTopicSub${EmailIndex}&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;
&lt;span class="nn"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, this is all good, but we still need to get the actual emails into the resource definition. If you think about the comma separated list of emails, you will notice that they can be converted into an array using the &lt;a href="https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference-split.html"&gt;&lt;code&gt;Fn::Split&lt;/code&gt; function&lt;/a&gt; the following way:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="kt"&gt;!Split&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;,'&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;!Ref&lt;/span&gt; &lt;span class="nv"&gt;Subscribers&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once that's done, we now just need to reference the right items. This is where we will use the original &lt;code&gt;EmailIndex&lt;/code&gt; variable. Users need to make sure that it's been set correctly, as it will fail otherwise. I don't cover it here, but it would be possible to setup some validation &lt;a href="https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/rules-section-structure.html"&gt;Rules&lt;/a&gt; by following the &lt;a href="https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/rules-section-structure.html"&gt;documentation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;After that, we jut need to access the right items by using the &lt;a href="https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference-select.html"&gt;&lt;code&gt;Fn::Select&lt;/code&gt; function&lt;/a&gt;. For example in this case:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="kt"&gt;!Select&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;!Sub&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;${EmailIndex}"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;!Split&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;,'&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;!Ref&lt;/span&gt; &lt;span class="nv"&gt;Subscribers&lt;/span&gt;&lt;span class="pi"&gt;]]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Putting al this together, we will get the following template. &lt;em&gt;(just make sure you set the index params right during deployment)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TLDR:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;AWSTemplateFormatVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;2010-09-09&lt;/span&gt;
&lt;span class="na"&gt;Transform&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; 
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;AWS::LanguageExtensions'&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;AWS::Serverless-2016-10-31'&lt;/span&gt;
&lt;span class="na"&gt;Description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Sample Cloudformation file for SNS subscriptions&lt;/span&gt;
&lt;span class="na"&gt;Parameters&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;Subscribers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;String&lt;/span&gt;
    &lt;span class="na"&gt;Description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Comma separated list of subscribers&lt;/span&gt;
    &lt;span class="na"&gt;Default&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;
  &lt;span class="na"&gt;SubscriberIndexes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;String&lt;/span&gt;
    &lt;span class="na"&gt;Description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
      &lt;span class="s"&gt;Comma separated list of indexes.&lt;/span&gt;
      &lt;span class="s"&gt;Should start from 0 and should be in sequence upto the number of subscribers.&lt;/span&gt;

      &lt;span class="s"&gt;It is used as a helper to create unique logical ids for subscriptions.&lt;/span&gt;
    &lt;span class="na"&gt;Default&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;
&lt;span class="na"&gt;Resources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;SampleTopic&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;AWS::SNS::Topic&lt;/span&gt;
    &lt;span class="na"&gt;Properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;DisplayName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Sample Topic&lt;/span&gt;
      &lt;span class="na"&gt;TopicName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;sample-topic&lt;/span&gt;
  &lt;span class="s"&gt;Fn::ForEach::Subscriptions:&lt;/span&gt;
      &lt;span class="s"&gt;- EmailIndex&lt;/span&gt;
      &lt;span class="s"&gt;- !Split [',', !Ref SubscriberIndexes]&lt;/span&gt;
      &lt;span class="s"&gt;- SampleTopicSub${EmailIndex}&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;AWS::SNS::Subscription&lt;/span&gt;
          &lt;span class="na"&gt;Properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;Endpoint&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;!Select&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;!Sub&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;${EmailIndex}"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;!Split&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;,'&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;!Ref&lt;/span&gt; &lt;span class="nv"&gt;Subscribers&lt;/span&gt;&lt;span class="pi"&gt;]]&lt;/span&gt;
            &lt;span class="na"&gt;Protocol&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;email&lt;/span&gt;
            &lt;span class="na"&gt;TopicArn&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;!Ref&lt;/span&gt; &lt;span class="s"&gt;SampleTopic&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>aws</category>
      <category>tutorial</category>
      <category>devops</category>
      <category>infrastructureascode</category>
    </item>
  </channel>
</rss>
