Mastering Secure Kubernetes-to-S3 Access with Terraform 

31 Oct, 2023 | 9 minutes read

In today’s cloud-native landscape, Kubernetes has emerged as a powerful orchestrator for containerized applications, enabling seamless scaling, deployment, and management. With the rise of Kubernetes, the need to securely interact with cloud storage services, like AWS S3, has become increasingly vital. Ensuring that your Kubernetes pods can access S3 buckets securely is not only a best practice but also a critical aspect of maintaining the integrity and confidentiality of your data. 

In this comprehensive guide, we will explore the art of establishing secure communication between a Kubernetes pod and an AWS S3 bucket, all while harnessing the might of Terraform for infrastructure as code (IaC). Our journey will take us through the creation of the S3 bucket, definition of access policies, management of object lifecycles, and the configuration of IAM roles and service accounts. By the end of this tutorial, you’ll be equipped with the knowledge to safeguard your data in the cloud. 

So, fasten your seatbelts, because we’re about to embark on an expedition into the world of secure Kubernetes-to-S3 access, using Terraform as our trusty guide. Whether you’re a seasoned DevOps engineer or just starting to navigate the cloud-native waters, this guide will provide you with the know-how to ensure that your containerized applications interact with AWS S3 both securely and seamlessly. 

Setting up the AWS S3 Bucket 

The foundation of enabling secure access from Kubernetes pods to AWS S3 is the creation of an S3 bucket. In this section, we’ll guide you through the process of setting up the AWS S3 bucket using Terraform, ensuring that it’s configured to meet the specific requirements of your cloud-native infrastructure. 

Terraform Resources for AWS S3 Bucket Setup

We begin by defining the necessary Terraform resources for creating the S3 bucket and specifying its access control. 

resource "aws_s3_bucket" "bucket" {
  bucket = "my-s3-bucket"
}

Bucket Creation: We create an S3 bucket named “my-s3-bucket.” 

Customizing Your S3 Bucket

Your S3 bucket setup can be further customized to meet the unique demands of your applications. You can adjust the ACL and bucket policies, implement versioning, and configure logging and monitoring to suit your specific needs. 

By starting with a well-configured S3 bucket, you lay the groundwork for secure access from your Kubernetes pods. The subsequent sections of this guide will build upon this foundation, culminating in a secure and efficient Kubernetes-to-S3 access setup. 

Access Control for AWS S3 Buckets 

AWS S3 provides a flexible system for managing access control through Access Control Lists (ACLs). These ACLs define who can access the objects within a bucket and what actions they can perform. When configuring an AWS S3 bucket, it’s essential to define the appropriate ACLs to ensure that only authorized entities can interact with the data. 

In our journey towards enabling secure access from Kubernetes pods to AWS S3 buckets, precise access control is paramount. In this section, we’ll explore how to control and manage access to an AWS S3 bucket through AWS S3 bucket access control lists (ACLs), using the code example below: 

resource "aws_s3_bucket_acl" "bucket_acl" {
  bucket = aws_s3_bucket.bucket.id
 acl	= "private"

in this code, we specify that the access control list (ACL) for the “my-s3-bucket” S3 bucket should be set to “private.” This ensures that access to the bucket is restricted, and only authorized entities, as defined in your IAM policies and service accounts, can interact with it. 

As we continue towards securing Kubernetes-to-AWS S3 access, we’ll explore the critical role of IAM policies, which grant precise permissions to your Kubernetes service accounts, thereby ensuring that your pods can interact securely with AWS S3. 

AWS S3 bucket policies define the permissions and access control rules that dictate who can interact with the objects contained within an S3 bucket. These policies are expressed in JSON format and play a crucial role in securing your data. When configuring an S3 bucket, it’s essential to craft policies that align with your security requirements. 

The provided code snippet exemplifies a policy that permits public access to objects within the S3 bucket with a specific prefix.

resource "aws_s3_bucket_policy" "bucket_policy" {
  bucket = aws_s3_bucket.bucket.id
  policy = <<POLICY
{
	"Version": "2012-10-17",
	"Id": "Policy1415115909152",
	"Statement": [
    	{
        	"Sid": "Access-to-pub",
        	"Effect": "Allow",
        	"Principal": "*",
        	"Action": "s3:GetObject",
        	"Resource": "${aws_s3_bucket.bucket.arn}/public/*"
    	}
	]
}
POLICY
}

Kubernetes-Managed AWS S3 Object Lifecycle 

In the realm of cloud-native applications, efficient management of data is paramount. Kubernetes not only excels in orchestrating containers but can also play a pivotal role in governing the lifecycle of AWS S3 objects. In this section, we explore how Kubernetes can streamline the management of your S3 data.

Utilizing Kubernetes for S3 Object Lifecycle

One of the key advantages of using Kubernetes is its versatility. Beyond managing containers, Kubernetes can also help manage the lifecycle of your S3 objects. This means that you can automate the process of removing outdated or redundant data from your S3 bucket. Kubernetes offers a robust solution for this by defining rules and expiration conditions for your objects. 

Terraform Resource for S3 Object Lifecycle Configuration

In our Terraform infrastructure code, we utilize the aws_s3_bucket_lifecycle_configuration resource to configure the S3 object lifecycle. This resource allows you to define specific rules that govern the objects’ lifetimes. Below is a snippet of the Terraform code used to achieve this: 

resource "aws_s3_bucket_lifecycle_configuration" "l1" {
  bucket = aws_s3_bucket.bucket.id
  rule {
	status = "Enabled"
	id     = "expire_all_files"
	filter {
  	prefix = "public/"
	}
	expiration {
  	days = 1
	}
  }
}

This snippet demonstrates how you can set a rule to automatically expire objects in the “public/” prefix after one day. Such configurations can help you maintain data integrity, reduce storage costs, and ensure compliance with data retention policies. 

IAM Policies for Kubernetes Service Accounts 

In our mission to establish secure Kubernetes-to-AWS S3 access, IAM (Identity and Access Management) policies play a pivotal role. In this section, we’ll explore how you can create and attach IAM policies to Kubernetes service accounts, enhancing access control and security within your cluster. 

Creating an IAM Policy for Kubernetes Service Accounts

To define the actions and resources that your Kubernetes service accounts are permitted to access, you can craft a custom IAM policy. This policy specifies the permissions and conditions under which your pods can interact with AWS services, including S3. 

Below is an example of how to create an IAM policy in Terraform: 

resource "aws_iam_policy" "s3_sa_policy" {
  name   = "s3-sa-policy"
  policy = <<POLICY
{
	"Version": "2012-10-17",
	"Statement": [
    	{
        	"Effect": "Allow",
        	"Action": [
            	"s3:DeleteObject",
            	"s3:GetObject",
            	"s3:GetObjectAcl",
            	"s3:PutObject",
            	"s3:PutObjectAcl",
            	"s3:ListBucket"
        	],
        	"Resource": "${aws_s3_bucket.bucket.arn}/*",
        	"Condition": {
            	"StringEquals": {
                	"aws:sourceVpce": "${aws_vpc_endpoint.s3.id}"
            	}
        	}
    	}
	]
}
POLICY
}

In the above code example, we define a policy that grants various S3-related permissions to pods associated with the Kubernetes service account, including s3:DeleteObject, s3:GetObject, s3:GetObjectAcl, and more. The policy also specifies conditions, such as limiting access to resources within a VPC endpoint. 

Creating an IAM Role

Next, we have to create an IAM Role to associate the S3 Service Account policy to it: 

resource "aws_iam_role" "s3_sa_role" {
  name = "s3-sa-role"
 
  assume_role_policy = <<ROLE
{
  "Version": "2012-10-17",
  "Statement": [
	{
  	"Effect": "Allow",
  	"Principal": {
    	"Federated": "arn:aws:iam::${data.aws_caller_identity.current.account_id}:oidc-provider/${replace(data.aws_eks_cluster.cluster.identity[0].oidc[0].issuer, "https://", "")}"
      },
  	"Action": "sts:AssumeRoleWithWebIdentity",
  	"Condition": {
    	"StringEquals": {
          "${replace(data.aws_eks_cluster.cluster.identity[0].oidc[0].issuer, "https://", "")}:aud": "sts.amazonaws.com"
    	}
  	}
	}
  ]
}
ROLE
}

Associating the IAM Policy with the IAM Role

Once you’ve created the IAM policy, the next step is to attach it to your IAM Role 

This association can be achieved through Terraform as well. Below is a code snippet that demonstrates how to attach the previously defined IAM policy to a IAM Role: 

resource "aws_iam_role_policy_attachment" "s3_sa_policy_attach" {
  policy_arn = aws_iam_policy.s3_sa_policy.arn
  role       = aws_iam_role.s3_sa_role.name
}

The code attaches the IAM policy (aws_iam_policy.s3_sa_policy) to the IAM role (aws_iam_role.s3_sa_role) associated with the Kubernetes service account. This creates a seamless connection between the policy and the pods, granting them the specified permissions. 

Fine-Tuning Access Control for Kubernetes Pods

By creating custom IAM policies and associating them with Kubernetes service accounts, you can fine-tune access control for your pods. This level of control is essential for ensuring that your pods can securely and selectively interact with AWS S3, all within the context of your Kubernetes environment. 

In the next section, we’ll explore the Kubernetes service account configuration, providing a bridge between IAM policies and your pods, and how this connection contributes to secure Kubernetes-to-S3 access. 

Kubernetes Service Account Configuration 

To establish a secure connection between your Kubernetes pods and AWS services like S3, you need to configure Kubernetes service accounts effectively. Service accounts act as the identity provider for your pods and are linked to AWS IAM roles through annotations. 

Below is a code example demonstrating the configuration of a Kubernetes service account and the annotation associating it with the IAM role: 

resource "kubernetes_service_account" "s3_sa" {
  automount_service_account_token = true
  metadata {
	name      = "s3-service-account"
	namespace = "default"
	annotations = {
  	"eks.amazonaws.com/role-arn" = aws_iam_role.s3_sa_role.arn
	}
  }
  depends_on = [
	module.eks,
	null_resource.get_kubeconfig
  ]
}

In this code, we configure a Kubernetes service account named “s3-service-account” and annotate it with the IAM role ARN, which links the service account to the IAM policy. This linkage is essential for establishing the identity and permissions of pods in the Kubernetes cluster. 

Enhancing Access Control and Security

Proper configuration of Kubernetes service accounts bridges the gap between IAM policies and Kubernetes pods, ensuring that pods can securely access AWS S3 while adhering to the defined permissions. This setup allows for fine-grained access control, aligning with the principle of least privilege. 

Ensuring Secure, Role-Based Access

Configuring Kubernetes service accounts is a pivotal step in the role-based access control (RBAC) of your Kubernetes cluster. It aligns with the principle of least privilege, ensuring that pods have precisely the permissions they need and nothing more. This approach not only enhances security but also streamlines management by centralizing permissions within IAM roles. 

As you proceed on your journey to enable Kubernetes pods to securely access AWS S3, remember that Kubernetes service accounts are the gateway through which your pods authenticate and acquire their permissions. With proper configuration, you establish a strong foundation for secure interactions between your containerized applications and cloud resources. 

Next, we will explore the deployment and testing of Kubernetes pods that utilize these service accounts and IAM policies, solidifying the practical aspects of secure Kubernetes-to-S3 access. 

Deployment and Testing of Kubernetes Pods 

Deployment is a fundamental step in ensuring your pods can utilize the configured service accounts and IAM policies. You can use Kubernetes manifest files or the kubectl command to create and deploy pods. 

Here’s a simple example of a Kubernetes manifest for deploying a pod: 

apiVersion: v1
kind: Pod
metadata:
  name: my-pod
spec:
  serviceAccountName: s3-service-account
  containers:
  - name: my-container
	image: your-container-image

In this manifest, we specify the service account name, “s3-service-account,” which has been configured to utilize the necessary IAM policy. The container image specified under containers represents the application or workload you wish to deploy. 

Testing Secure Access to AWS S3

Once the pods are deployed, it’s imperative to conduct testing to ensure that the secure access setup is functioning as expected. Verification should include checking that the pods can: 

  • Successfully authenticate using the Kubernetes service account. 
  • Access AWS S3 resources according to the permissions defined in the IAM policy. 
  • Perform required S3 actions, such as listing objects, retrieving data, or uploading content securely. 

You can use AWS CLI commands, SDKs, or specific tools within your application to interact with the S3 bucket and validate that access is both secure and aligned with the defined access control policies.

Conclusion 

In this journey through the realm of secure Kubernetes-to-S3 access, we’ve harnessed the power of Kubernetes to fortify the connection between your containerized applications and AWS S3. As we conclude, let’s highlight the key takeaways. 

By mastering Kubernetes and implementing the steps detailed in this guide, you’ve acquired the skills to establish a robust and secure communication channel. Kubernetes has proven to be your stalwart ally in orchestrating containerized applications while seamlessly ensuring data integrity and confidentiality. 

Kubernetes is more than just an orchestrator; it’s your gateway to secure cloud-native operations. The well-configured S3 bucket, precise access control through IAM policies, Kubernetes-managed object lifecycle, and fine-tuned access for your pods collectively reinforce the bond between Kubernetes and AWS S3. 

In this cloud-centric era, data protection is non-negotiable. With your newfound knowledge, you’re not only safeguarding your data but also bolstering the trust of your users and stakeholders. Kubernetes offers not just security but also reliability and operational excellence. 

With confidence in Kubernetes, secure your cloud-native world. Your journey has just begun, and with Kubernetes as your guide, you’re poised for success.