Skip to content

Commit

Permalink
Merge pull request #1 from Geartrixy/master
Browse files Browse the repository at this point in the history
initial commit
  • Loading branch information
derBroBro authored Jul 2, 2018
2 parents 910a108 + ad3a2e0 commit 0fa98ae
Show file tree
Hide file tree
Showing 29 changed files with 807 additions and 1 deletion.
19 changes: 19 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
## Release Version: 0.0.1

BACKWARDS INCOMPATIBILITIES / NOTES:

* Tested with terraform v0.11.7

INITIAL RELEASE:

* S3 Bucket: supports object versioning, lifecycle policy (on whole bucket) to remove object versions older than X days
* IAM Management Users: Admin, Sync
* Standard Users: User keys (directories) with KMS encryption for uploads

IMPROVEMENTS:

* N/A

BUG FIXES:

* N/A
160 changes: 159 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1 +1,159 @@
# terraform-aws-s3-with-iam-access
# AWS S3 Bucket with IAM Access Module
Terraform module which creates an S3 bucket with varying levels of access for IAM users.

The following resources can be created:
* An S3 bucket
* IAM User(s)
* IAM Policies
* KMS Keys

## Usage
### Specify this Module as Source
```hcl
module "s3" {
source = "git::https://github.com/zoitech/terraform-aws-s3-with-iam-access.git"
# Or to specifiy a particular module version:
source = "git::https://github.com/zoitech/terraform-aws-s3-with-iam-access.git?ref=v0.0.1"
```
### General Arguments
#### Resource Creation Location
The argument for the region is required to specify where the resources should be created:
```hcl
region = "eu-west-1" #default = "eu-central-1"
```
#### PGP Key
A public PGP key (in binary format) is required for encrypting the IAM secret keys and KMS keys, as these are given in output (Please see outputs below):
```hcl
pgp_keyname = "C123654C.pgp"
```
### S3 Bucket Arguments
#### Bucket Name
Set the bucket name:
```hcl
s3_bucket_name = "my-s3-bucket"
```
#### Object Versioning
Enable S3 object versioning:
```hcl
s3_versioning_enabled = true #default = false
```
#### Object Lifecycle
Enable S3 object lifecycle for the whole bucket and specify a rule name.

Object expiration and/or previous version deletion is specified in days:
```hcl
lifecycle_rule_enabled = true #default = false
lifecycle_rule_id = "expire_objects_older_than_180_days_delete_previous_versions_older_than_90_days" #default = ""
lifecycle_rule_expiration = 180 #default = 0
lifecycle_rule_noncurrent_version_expiration = 90 #default = 90
```

N.b. Object versioning must be enabled to expire current versions and delete previous versions of an object.

#### Bucket Lifecycle Prevent Destroy
By default the prevent_destroy lifecycle is to "true" to prevent accidental bucket deletion via terraform.

### IAM Bucket Management Users
#### IAM User(s): S3 Bucket Full Permissions
Create IAM user(s) with full S3 bucket permissions (These users receive both management console and programmatic access):
```hcl
iam_user_s3_full_names = ["superadmin1", "superadmin2"]
```
#### IAM User(s): S3 Bucket List/Delete Permissions
Create IAM user(s) with limited administrative (list and delete) S3 bucket permissions (These users receive both management console and programmatic access):
```hcl
iam_user_s3_list_delete_names = ["admin1", "admin2"]
```
#### IAM User(s): S3 Bucket Get/Delete Permissions
Create IAM user(s) with limited administrative (get and delete) S3 bucket permissions (These users receive only programmatic access)

Recommended as a synchronisation user:
```hcl
iam_user_s3_get_delete_names = ["sync_user", "sync_user2"]
```
### IAM Bucket Standard Users
Create IAM user(s) with their own bucket key (directory) in the S3 bucket. These users are assigned their own KMS keys which enable them to upload files in encrypted format as well as to download them and decrypt. (These users receive only programmatic access, therefore FTP client software such as CloudBerry or Cyberduck should be used):
```hcl
iam_user_s3_standard_names = ["Huey", "Dewey", "Louie"]
```

### Outputs
The following outputs are possible:
* bucket_name (The name of the S3 bucket)
* bucket_arn (The ARN of the S3 bucket)
* s3_full_user_info (The users with full S3 bucket permissions)
* s3_list_delete_user_info (The users with list/delete S3 bucket permissions)
* s3_get_delete_user_info (The users with get/delete S3 bucket permissions)
* standard_user_info (The users with access to their own S3 bucket keys)


Example usage:
```hcl
#The name of the S3 bucket
output "Bucket-Name" {
value = "${module.s3.bucket_name}"
}
#The ARN of the S3 bucket
output "Bucket-ARN" {
value = "${module.s3.bucket_arn}"
}
#The users with full S3 bucket permissions
output "Superadmins" {
value = "${module.s3.s3_full_user_info}"
}
#The users with list/delete S3 bucket permissions
output "Admins" {
value = "${module.s3.s3_list_delete_user_info}"
}
#The users with get/delete S3 bucket permissions
output "Sync-Users" {
value = "${module.s3.s3_get_delete_user_info}"
}
#The users with access to their own S3 bucket keys
output "User-Info" {
value = "${module.s3.standard_user_info}"
}
```

Example output:
```hcl
Admins = [
"user_name: Admin",
"access_key: <omitted>",
"secret_key: <omitted>",
"password": <omitted>"
]
Bucket-ARN = arn:aws:s3:::my-s3-bucket
Bucket-Name = my-s3-bucket
Superadmins = [
"user_name: superadmin",
"access_key: <omitted>",
"secret_key: <omitted>",
"password": <omitted>"
]
Sync-Users = [
"user_name: sync-user",
"access_key: <omitted>",
"secret_key: <omitted>"
]
User-Info = [
"user_name: Huey",
"access_key: <omitted>",
"secret_key: <omitted>",
"kms_key: <omitted>",
"bucket_key: my-s3-bucket/Huey"
"user_name: Dewey",
"access_key: <omitted>",
"secret_key: <omitted>",
"kms_key: <omitted>",
"bucket_key: my-s3-bucket/Dewey"
"user_name: Louie",
"access_key: <omitted>",
"secret_key: <omitted>",
"kms_key: <omitted>",
"bucket_key: my-s3-bucket/Louie"
]
```
38 changes: 38 additions & 0 deletions data_template_bucket_policy.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# template file for policy section: denying the unencrypted uploads
data "template_file" "bucket_policy_for_deny_unencrypted" {
template = "${file("${path.module}/templates/bucket_policies/bucket_policy_deny_unencrypted.json.tpl")}"

vars {
bucket-arn = "${aws_s3_bucket.s3_bucket.arn}"
}
}

# template file for policy section: standard users
data "template_file" "bucket_policy_for_a_standard_user" {
count = "${length(var.iam_user_s3_standard_names)}"
template = "${file("${path.module}/templates/bucket_policies/bucket_policy_user_template.json.tpl")}"

vars {
bucket-arn = "${aws_s3_bucket.s3_bucket.arn}"
user-name = "${element(aws_iam_user.standard_user.*.name, count.index)}"
kms-key = "${element(aws_kms_key.kmskey.*.key_id, count.index)}"
}
}

# combine policy sections into one
data "template_file" "bucket_policy" {
template = <<JSON
$${policy_start}
$${deny_unencrypted_object_uploads}
$${user_policies}
$${policy_end}
JSON

vars {
policy_start = "${file("${path.module}/templates/bucket_policies/bucket_policy_start.json.tpl")}"
deny_unencrypted_object_uploads = "${data.template_file.bucket_policy_for_deny_unencrypted.rendered}"
user_policies = "${join(",\n", data.template_file.bucket_policy_for_a_standard_user.*.rendered)}"
policy_end = "${file("${path.module}/templates/bucket_policies/bucket_policy_end.json.tpl")}"
}
}
87 changes: 87 additions & 0 deletions data_template_outputs.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
# template file for the S3 full permission user output
data "template_file" "s3_full_user_output" {
count = "${local.count_iam_user_s3_full_names}"
template = "${file("${path.module}/templates/outputs/s3_full_users.tpl")}"

vars {
user-name = "${element(aws_iam_user.iam_user_s3_full_access.*.name, count.index)}"
access-key = "${element(aws_iam_access_key.iam_user_s3_full_access.*.id, count.index)}"
secret-key = "${element(aws_iam_access_key.iam_user_s3_full_access.*.encrypted_secret, count.index)}"
password = "${element(aws_iam_user_login_profile.s3_full_login.*.encrypted_password, count.index)}"
}
}

# combine the S3 full permission user outputs together
data "template_file" "s3_full_user_outputs" {
template = "$${outputs}"

vars {
outputs = "${join("\n\n", data.template_file.s3_full_user_output.*.rendered)}"
}
}

# template file for the S3 list/delete permission user output
data "template_file" "s3_list_delete_user_output" {
count = "${local.count_iam_user_s3_list_delete_names}"
template = "${file("${path.module}/templates/outputs/s3_list_delete_users.tpl")}"

vars {
user-name = "${element(aws_iam_user.iam_user_s3_list_delete_access.*.name, count.index)}"
access-key = "${element(aws_iam_access_key.iam_user_s3_list_delete_access.*.id, count.index)}"
secret-key = "${element(aws_iam_access_key.iam_user_s3_list_delete_access.*.encrypted_secret, count.index)}"
password = "${element(aws_iam_user_login_profile.s3_list_delete_login.*.encrypted_password, count.index)}"
}
}

# combine the S3 list/delete permission user outputs together
data "template_file" "s3_list_delete_user_outputs" {
template = "$${outputs}"

vars {
outputs = "${join("\n\n", data.template_file.s3_list_delete_user_output.*.rendered)}"
}
}

# template file for the S3 get/delete permission user output
data "template_file" "s3_get_delete_user_output" {
count = "${local.count_iam_user_s3_get_delete_names}"
template = "${file("${path.module}/templates/outputs/s3_get_delete_users.tpl")}"

vars {
user-name = "${element(aws_iam_user.iam_user_s3_get_delete_access.*.name, count.index)}"
access-key = "${element(aws_iam_access_key.iam_user_s3_get_delete_access.*.id, count.index)}"
secret-key = "${element(aws_iam_access_key.iam_user_s3_get_delete_access.*.encrypted_secret, count.index)}"
}
}

# combine the S3 list/delete permission user outputs together
data "template_file" "s3_get_delete_user_outputs" {
template = "$${outputs}"

vars {
outputs = "${join("\n\n", data.template_file.s3_get_delete_user_output.*.rendered)}"
}
}

# template file for the standard user output
data "template_file" "standard_user_output" {
count = "${local.count_standard_user}"
template = "${file("${path.module}/templates/outputs/standard_users.tpl")}"

vars {
user-name = "${element(aws_iam_user.standard_user.*.name, count.index)}"
access-key = "${element(aws_iam_access_key.iam_user_standard_access.*.id, count.index)}"
secret-key = "${element(aws_iam_access_key.iam_user_standard_access.*.encrypted_secret, count.index)}"
kms-key = "${element(aws_kms_key.kmskey.*.key_id, count.index)}"
bucket-name = "${aws_s3_bucket.s3_bucket.id}"
}
}

# combine the standard user outputs together
data "template_file" "standard_user_outputs" {
template = "$${outputs}"

vars {
outputs = "${join("\n\n", data.template_file.standard_user_output.*.rendered)}"
}
}
6 changes: 6 additions & 0 deletions iam_access_keys.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#access keys for the standard users
resource "aws_iam_access_key" "iam_user_standard_access" {
count = "${local.count_standard_user}"
user = "${element(aws_iam_user.standard_user.*.name, count.index)}"
pgp_key = "${base64encode(file("${var.pgp_keyname}"))}"
}
42 changes: 42 additions & 0 deletions iam_policy.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# iam policy for the standard users
resource "aws_iam_policy" "iam_policy_standard_user" {
count = "${local.count_standard_user}"
name = "${aws_s3_bucket.s3_bucket.bucket}-${element(aws_iam_user.standard_user.*.name, count.index)}-policy"
path = "/"
description = "Grants ${element(aws_iam_user.standard_user.*.name, count.index)} download and upload access to the respective S3 folder for ${aws_s3_bucket.s3_bucket.bucket}"

policy = <<EOF
{
"Version":"2012-10-17",
"Statement": [
{
"Sid": "AllowUserToSeeBucketListInTheConsole",
"Action": ["s3:ListAllMyBuckets", "s3:GetBucketLocation"],
"Effect": "Allow",
"Resource": ["${aws_s3_bucket.s3_bucket.arn}:*"]
},
{
"Sid": "AllowRootListingOfBucket",
"Action": ["s3:ListBucket"],
"Effect": "Allow",
"Resource": ["${aws_s3_bucket.s3_bucket.arn}"],
"Condition":{"StringEquals":{"s3:prefix":["${element(aws_iam_user.standard_user.*.name, count.index)}/"],"s3:delimiter":["/"]}}
},
{
"Sid": "AllowListingOfUserFolder",
"Action": ["s3:ListBucket"],
"Effect": "Allow",
"Resource": ["${aws_s3_bucket.s3_bucket.arn}"],
"Condition":{"StringLike":{"s3:prefix":["${element(aws_iam_user.standard_user.*.name, count.index)}/*"]}}
},
{
"Sid": "AllowAllS3ActionsInUserFolder",
"Effect": "Allow",
"Action": ["s3:PutObject", "s3:GetObject"],
"Resource": ["${aws_s3_bucket.s3_bucket.arn}/${element(aws_iam_user.standard_user.*.name, count.index)}/*"]
}
]
}
EOF
}
20 changes: 20 additions & 0 deletions iam_static_user_access_keys.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# iam access keys for full permission users
resource "aws_iam_access_key" "iam_user_s3_full_access" {
count = "${local.count_iam_user_s3_full_names}"
user = "${element(aws_iam_user.iam_user_s3_full_access.*.name, count.index)}"
pgp_key = "${base64encode(file("${var.pgp_keyname}"))}"
}

# iam access keys for list delete permission users
resource "aws_iam_access_key" "iam_user_s3_list_delete_access" {
count = "${local.count_iam_user_s3_list_delete_names}"
user = "${element(aws_iam_user.iam_user_s3_list_delete_access.*.name, count.index)}"
pgp_key = "${base64encode(file("${var.pgp_keyname}"))}"
}

# iam access keys for get delete permission users
resource "aws_iam_access_key" "iam_user_s3_get_delete_access" {
count = "${local.count_iam_user_s3_get_delete_names}"
user = "${element(aws_iam_user.iam_user_s3_get_delete_access.*.name, count.index)}"
pgp_key = "${base64encode(file("${var.pgp_keyname}"))}"
}
Loading

0 comments on commit 0fa98ae

Please sign in to comment.