How to create a S3 bucket policy for the multiple existing manually created (not through terraform) s3 buckets using terraform - terraform-provider-aws

How to create a S3 bucket policy for the multiple existing manually created (not through terraform) s3 buckets using terraform
For Example : I have A,B,C buckets created manually and now I wanted to add a s3 buket policy for all 3 S3 buckets , How can I achieve this through Terraform? Can we use some loop sort of thing here Please advise

Do you want the same policy applied to each bucket? That doesn't really work because the policies need to include the bucket name in the resource section. It's a weird limitation of S3 bucket policies that I've never quite understood, you can't use a wildcard (*) for the bucket name.
Anyways, you could do something like this, where you dynamically set the bucket name in the policy.
I'm just typing this from memory so please excuse any syntax errors.
locals {
// The names of the buckets you want to apply policies to
buckets = [
"mybucket",
"anotherbucket",
]
}
// Create a unique policy for each bucket, using
// the bucket name in the policy.
data "aws_iam_policy_document" "bucket_policies" {
for_each = toset(local.buckets)
statement {
actions = [
"s3:PutObject"
]
resources = [
"arn:aws:s3:::${each.key}/*"
]
principals {
type = "AWS"
identifiers = [
var.my_user_arn
]
}
}
}
// Apply each policy to its respective bucket
resource "aws_s3_bucket_policy" "policies" {
for_each = toset(local.buckets)
bucket = each.key
policy = data.aws_iam_policy_document.bucket_policies[each.key].json
}

Related

How to iterate elements list and map in Terraform

I want to create a folder structure in S3 with Terraform so that it defaults to all environments. The idea is to have structures similar to these:
locals {
folder = [
{
provider = "provider-1",
process = "batch-process",
final = ["people","cart"]
},
{
provider = "provider-1",
process = "online-process",
final = ["log","order"]
}]}
Bucket-1
provider-1
batch-process
people
cart
online-process
log
order
I managed to create a list with all the S3 directories I would like to have, but I know this is not the most efficient way.
I tried to follow some examples found here but they returned an error. What is the correct way to do this iteration without having to write the entire directory?

Terraform issue attaching a security group to my aws instances

I'm new enough to terraform and think I am misunderstanding something with count and count.index usage.
I am creating some EC2 instances using the count parameter and it works fine
resource "aws_instance" "server" {
ami = data.aws_ami.app_ami.id
instance_type = "t2.micro"
key_name = "DeirdreKey"
subnet_id = aws_subnet.my_subnet_a.id
count = 2
tags = {
Name = "server.${count.index}"
}
I want to associated a security group with both instances so I created the below
resource "aws_network_interface_sg_attachment" "sg_attachment" {
security_group_id = aws_security_group.allow_internet.id
network_interface_id = aws_instance.server.primary_network_interface_id
}
However I am running into this error
Error: Missing resource instance key
on lb.tf line 57, in resource "aws_network_interface_sg_attachment" "sg_attachment":
57: network_interface_id = aws_instance.server.primary_network_interface_id
Because aws_instance.server has "count" set, its attributes must be
accessed on specific instances.
For example, to correlate with indices of a referring resource, use:
aws_instance.server[count.index]
I understand what the error is complaining about . Its because the local resource name I am referring to in not unique as I have created a count of 2 aws instances called "server". I dont know how to fix it though. I tried with the below
resource "aws_network_interface_sg_attachment" "sg_attachment" {
security_group_id = aws_security_group.allow_internet.id
network_interface_id = aws_instance.server[count.index].primary_network_interface_id
But then I get the below error
Error: Reference to "count" in non-counted context
on lb.tf line 53, in resource "aws_network_interface_sg_attachment" "sg_attachment":
53: network_interface_idaws_instance.server[count.index].primary_network_interface_id
The "count" object can only be used in "module", "resource", and "data"
blocks, and only when the "count" argument is set.
Does this mean I have to introduce the count.index into the local resource name? I tried it a few ways and it doesnt seem to work
resource "aws_instance" "server${count.index}" {
You need a count statement on the resource to use count.index. Count statements can get out of hand, so if you have multiple resources that logically need the same count, use a variable or local value:
local {
replications = 2
}
resource "aws_instance" "server" {
count = local.replications
ami = data.aws_ami.app_ami.id
instance_type = "t2.micro"
key_name = "DeirdreKey"
subnet_id = aws_subnet.my_subnet_a.id
tags = {
Name = "server.${count.index}"
}
}
resource "aws_network_interface_sg_attachment" "sg_attachment" {
count = local.replications
security_group_id = aws_security_group.allow_internet.id
network_interface_id = aws_instance.server[count.index].primary_network_interface_id
}
This creates one security group attachment per server, and gives you a list of servers you can reference as aws_instance.server[0] and aws_instance.server[1], and a list of attachments that you can reference in the same way.

Firebase indexes on dynamically created keys

I am trying to use Firebase index on the realtime database, the problem I have is that the data key is created programmically and has an incremental value at the end of the key.
For example;
match_01, match_02, match_03, etc...
The structure is;
- Matches
- Match_01
- played
- hometeam
- awayteam
etc....
I've look at how to setup Firebase rules that defines the index, but this seems to only be applicable to known data, not data that has a dynamically generated key. The code below for example won't work as the parent of played is Match_01, Match_02, etc...
{
"rules": {
"Matches": {
".indexOn": ".played"
}
}
}
Does anyone know how to set an index against this type of data structure?

Custom security rules for Cloud Firestore

I want to create a Cloud Firestore realtime database containing groups which users can join and share information to other members of their group. I want to preserve users anonymity so the way I see it to be implemented is:
Group creator generates a group key in format XXXX-XXXX-XXXX-XXXX
Those who want to join must have the group key which they enter in the app, after that they should be able to read, create and update data in that group
So basically the data structure is something like this:
/groups/ : [
//groups as documents
"ABCD-0000-0000-0001" : { /*group data model*/ }
"ABCD-0000-0000-0002" : { /*group data model*/ }
"ABCD-0000-0000-0003" : { /*group data model*/ }
]
The question is, what security rules should I write to permit users to read, create and update data ONLY in the group they belong to (have its group key)? At the same time, how to forbid users from finding out other groups' keys?
Your group structure can remain as is-
groups (Collection) : [
//groups as documents
"ABCD-0000-0000-0001" : { /*group data model*/ }
"ABCD-0000-0000-0002" : { /*group data model*/ }
"ABCD-0000-0000-0003" : { /*group data model*/ } ]
And to maintain the access, you can have another separate collection named group_users as-
group_users(Collection)/ <group_id>(Document)/ members(Collection)/ :
uid_1 (document)
uid_2 (document)
...
Now the rule to allow can be like-
service cloud.firestore {
match /databases/{database}/documents {
match /groups/{group_id} {
allow read, create, update: if exists(/databases/$(database)/documents/group_users/$(group_id)/members/$(request.auth.uid));
}
}
}
When a member joins the group, you will have to add the user's uid to that new collection-
group_users/<group_id>/members
For admins, you can have a similar collection, and uid will be added when the admin creates the group-
group_users/<group_id>/admins
Instead of having a separate collection outside of groups collection, you could have a collection within group itself as an alternative solition, then you will have to modify the group data model to some more extent.
Also FYI, each exists () call in security rules is billed (probably as one read operation).
And here is a detailed documentation explaining almost every possible aspect of firestore security rules.
You can save the group ID in the user's profile. Then create a rule which only allows CRU permissions if that group ID exists.
db.collection.('users').doc({userId}.update({
ABCD-0000-0000-0001: true
})
match /groups/{groupId} {
allow read, create, update: if get(/databases/$(database)/documents/users/$(request.auth.uid)).data.$(groupId) == true;
}

How can I grant access to array of admins on Firebase database rules

I am stuck trying to allow an an array of admins access to their data.
I have a database structure like this:
{
"Respondents": {
"Acme Corp": {
"admins": ["mMK7eTrRL4UgVDh284HntNRETmx1", ""mx1TERNmMK7eTrRL4UgVDh284Hnt"],
"data": {data goes here...}
},
"Another Inc": {
"admins": ["Dh284HmMK7eTrRL4UgVDh284HntN", ""x1TERNmx1TERNmMK7eTrRL4UgVDh"],
"data": {their data goes here...}
}
}
}
And then I tried to set my rules like this
{
"rules": {
"Respondents": {
"$organisation" : {
".read": "root.child('Respondents').child($organisation).child('admins').val().includes(auth.id)",
".read": "root.child('Respondents').child($organisation).child('admins').val().includes(auth.id)"
}
}
}
}
..but that won't parse in the Firebase Database Rules editor
I get "Error saving rules - Line 7: No such method/property 'includes'", but I need something to match the user id with the array of admins.
Any experience or suggestions?
As you've found, there is no includes() operation in Firebase's security rules. This is because Firebase doesn't actually store the data as an array. If you look in the Firebase Database console or read this blog post you will see that Firebase stores it as a regular object:
"admins": {
"0": "mMK7eTrRL4UgVDh284HntNRETmx1",
"1": "mx1TERNmMK7eTrRL4UgVDh284Hnt"
}
And since that is a regular JavaScript object, there is no contains() method on it.
In general creating arrays are an anti-pattern in the Firebase Database. They're often the wrong data structure and when used are regularly the main cause of scalability problems.
In this case: you're not really looking to store a sequence of UIDs. In fact: the order of the UIDs doesn't matter, and each UID can be meaningfully present in the collection at most once. So instead of an array, you're looking to store set of uids.
To implement a set in Firebase, you use this structure:
"admins": {
"mMK7eTrRL4UgVDh284HntNRETmx1": true,
"mx1TERNmMK7eTrRL4UgVDh284Hnt": true
}
The value doesn't matter much. But since you must have a value to store a key, it is idiomatic to use true.
Now you can test whether a key with the relevant UID exists under admins (instead of checking whether it contains a value):
"root.child('Respondents').child($organisation).child('admins').child(auth.uid).exists()",

Resources