mantil-io / mantil

Build your AWS Lambda-based Go backends quicker than ever
https://www.mantil.com
MIT License
110 stars 3 forks source link

Set only necessary permissions for node lambda functions #23

Closed IvanVlasic closed 2 years ago

IvanVlasic commented 3 years ago

Currently in terraform all lambdas and roles have all permissions. We should probably narrow this down to only necessary permissions.

ianic commented 2 years ago

Ovo takodjer treba osigurati da backend iz jednog workspace nikako ne moze doci do stages koji su vezani za neki drugi workspace.

ianic commented 2 years ago

Maknuti po kodu nagomilane: // TODO permissions zamjeniti ispravnim policy.

IvanVlasic commented 2 years ago

Krenuo sam sa ws lambdama, implementacija je u gore navedenom commitu.

Na pocetku je potrebno napomenuti da nemaju svi servisi iste opcije permissiona. Npr za invokanje lambdi se ne moze dodati condition po tagovima, cijeli popis svih servisa i opcija je dostupan ovdje.

Permissione sam testirao rucno i preko iam policy simulatora.

Prva je ws_handler lambda koja dobiva requeste od API gatewaya i invoka projektne lambde. IAM policy izgleda ovako:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "",
            "Effect": "Allow",
            "Action": "lambda:InvokeFunction",
            "Resource": "arn:aws:lambda:*:*:function:project-dev-*-ep3dmji"
        },
        {
            "Sid": "",
            "Effect": "Allow",
            "Action": [
                "dynamodb:Query",
                "dynamodb:PutItem",
                "dynamodb:GetItem",
                "dynamodb:DescribeTable",
                "dynamodb:DeleteItem",
                "dynamodb:BatchWriteItem",
                "dynamodb:BatchGetItem"
            ],
            "Resource": "arn:aws:dynamodb:*:*:table/project-dev-ws-connections-ep3dmji"
        },
        {
            "Sid": "",
            "Effect": "Allow",
            "Action": [
                "logs:PutLogEvents",
                "logs:CreateLogStream"
            ],
            "Resource": "*"
        }
    ]
}

Lambdi dajem pravo da invoka lambde cije je ime template project-dev-*-ep3dmji sto ce biti samo lambde od tog jednog stagea, prava na dynamodb tablicu koja je kreirana unaprijed specificno za tu potrebu i prava za pisanje logova.

ws_forwarder lambda prima odgovore od projektnih lambdi i salje odgovor preko api gatewaya. Prava izgledaju ovako:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "",
            "Effect": "Allow",
            "Action": "execute-api:ManageConnections",
            "Resource": "arn:aws:execute-api:*:*:56832zuocl/*"
        },
        {
            "Sid": "",
            "Effect": "Allow",
            "Action": [
                "dynamodb:Query",
                "dynamodb:PutItem",
                "dynamodb:GetItem",
                "dynamodb:DescribeTable",
                "dynamodb:DeleteItem",
                "dynamodb:BatchWriteItem",
                "dynamodb:BatchGetItem"
            ],
            "Resource": "arn:aws:dynamodb:*:*:table/project-dev-ws-connections-ep3dmji"
        },
        {
            "Sid": "",
            "Effect": "Allow",
            "Action": [
                "logs:PutLogEvents",
                "logs:CreateLogStream"
            ],
            "Resource": "*"
        }
    ]
}

Tu se ponavljaju prava za dynamodb tablicu i logove, i dodatno je tu ManageConnections na ws api tog stagea koji lambdi omogucuje da salje odgovore klijentima.

IvanVlasic commented 2 years ago

Sljedeca je CLI rola.

Njezina prava su:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "",
            "Effect": "Allow",
            "Action": "s3:PutObject",
            "Resource": "arn:aws:s3:::mantil-*-ep3dmji/*"
        },
        {
            "Sid": "",
            "Effect": "Allow",
            "Action": [
                "logs:FilterLogEvents",
                "logs:DescribeLogStreams"
            ],
            "Resource": "*",
            "Condition": {
                "StringEquals": {
                    "aws:resourceTag/MANTIL_KEY": [
                        "ep3dmji"
                    ],
                    "aws:resourceTag/MANTIL_WORKSPACE": [
                        "ivlasic"
                    ]
                }
            }
        }
    ]
}

Njoj dajem prava za pisanje u s3 buckete cije je ime teamplatea mantil-*-ep3dmji sto zadovoljava buckete svih projekata i stageova u nodu; glavni bucket u koji idu funkcije i public buckete u koji idu frontend asseti. PutObject ne podrzava tagove pa to nisam mogao rijesiti preko toga.

Za log grupe koristim tagove i dajem prava samo za one koji imaju key i workspace tag, sto ce ponovno biti sve log grupe tog nodea.

Dodatno ce se ovi permissioni jos vise suziti u security lambdi. Za s3 buckete cemo dodati specificna imena koja ce morati zadovoljavati gore navedeni template, a log grupe filtriramo po prefixu, no opet, sve grupe koje zadovoljavaju taj prefix ce ujedno morati i imati gore navedene tagove.

IvanVlasic commented 2 years ago

Dodao sam permissione za security i authorizer lambdu.

Security ima samo permissione za logove i assume cli-role.

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "",
            "Effect": "Allow",
            "Action": "sts:AssumeRole",
            "Resource": "arn:aws:iam::216684349989:role/mantil-cli-user-pp773ii"
        },
        {
            "Sid": "",
            "Effect": "Allow",
            "Action": [
                "logs:PutLogEvents",
                "logs:CreateLogStream"
            ],
            "Resource": "*"
        }
    ]
}

Authorizer ima permissione za logove:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "",
            "Effect": "Allow",
            "Action": [
                "logs:CreateLogStream",
                "logs:PutLogEvents"
            ],
            "Resource": "*"
        }
    ]
}

Ove preostale tri lambde - setup, deploy i destroy su se malo zakomplicirale jer se tu koristi jako puno permissiona pa gledam kako je najbolji nacin to posloziti. Jedna stvar koju sam primjetio do sad je da cemo mozda morati poraditi na imenima stage lambdi. Conditioni za lamda permissione se mogu stavljati samo na ime, a nemamo neki template koji koristimo za imena lambdi u stageu koji se moze reusati kao npr za setup gdje imamo mantil-*-id pa s trenutnim imenima jedina opcija je dati prava svim lambdama, sto nije bas optimalno, @ianic

ianic commented 2 years ago

A *-id ne moze funkcionirati?

IvanVlasic commented 2 years ago

Ah, glup sam. :D Svi projekti i stageovi ce imati isti node id, u pravu is. :)

IvanVlasic commented 2 years ago

Prava za lambde koje koriste terraform su malo opsirnija i teze je doci do njih. Trebamo ukljuciti sve api pozive koje radi terraform. Tu sam si pomogao sa IAM access analyzerom i cloudtrailom koji logira sve akcije pa tamo mogu vidjeti kakve sve permissione koristi koja rola, no nije savrseno pa ima malo metode pokusaja i pogreske.

Za deploy lambdu ima malo vise permissiona, no to je jedini nacin da ne obuhvacamo stvari koje ne bi trebali. Npr ne mogu staviti iam:* jer iam pored rola ima i druga prava poput usera i onda bi lambdi morao dati i prava na usere na aws accountu, sto nije prihvatljivo. Onda je jedina opcija imati ovako detaljnije granuliranje.

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "",
            "Effect": "Allow",
            "Action": [
                "apigateway:TagResource",
                "apigateway:PUT",
                "apigateway:POST",
                "apigateway:PATCH",
                "apigateway:GET",
                "apigateway:DELETE"
            ],
            "Resource": "*"
        },
        {
            "Sid": "",
            "Effect": "Allow",
            "Action": [
                "logs:UpdateLogDelivery",
                "logs:PutResourcePolicy",
                "logs:ListLogDeliveries",
                "logs:GetLogDelivery",
                "logs:DescribeResourcePolicies",
                "logs:DescribeLogGroups",
                "logs:CreateLogDelivery"
            ],
            "Resource": "*"
        },
        {
            "Sid": "",
            "Effect": "Allow",
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::mantil-releases*/*"
        },
        {
            "Sid": "",
            "Effect": "Allow",
            "Action": [
                "lambda:UpdateFunctionConfiguration",
                "lambda:UpdateFunctionCode",
                "lambda:ListVersionsByFunction",
                "lambda:GetPolicy",
                "lambda:GetFunctionConfiguration",
                "lambda:GetFunctionCodeSigningConfig",
                "lambda:GetFunction",
                "lambda:CreateFunction",
                "lambda:AddPermission"
            ],
            "Resource": "arn:aws:lambda:*:*:function:*-n3isbby"
        },
        {
            "Sid": "",
            "Effect": "Allow",
            "Action": [
                "logs:PutRetentionPolicy",
                "logs:PutLogEvents",
                "logs:ListTagsLogGroup",
                "logs:CreateLogStream",
                "logs:CreateLogGroup"
            ],
            "Resource": [
                "arn:aws:logs:*:*:log-group:*-n3isbby:log-stream:*",
                "arn:aws:logs:*:*:log-group:*-n3isbby"
            ]
        },
        {
            "Sid": "",
            "Effect": "Allow",
            "Action": [
                "iam:TagRole",
                "iam:PutRolePolicy",
                "iam:PassRole",
                "iam:ListRolePolicies",
                "iam:ListAttachedRolePolicies",
                "iam:GetRolePolicy",
                "iam:GetRole",
                "iam:CreateRole"
            ],
            "Resource": "arn:aws:iam::*:role/*-n3isbby"
        },
        {
            "Sid": "",
            "Effect": "Allow",
            "Action": [
                "s3:PutObject",
                "s3:PutBucketWebsite",
                "s3:PutBucketTagging",
                "s3:PutBucketPolicy",
                "s3:PutBucketAcl",
                "s3:ListBucket",
                "s3:GetReplicationConfiguration",
                "s3:GetObject",
                "s3:GetLifecycleConfiguration",
                "s3:GetEncryptionConfiguration",
                "s3:GetBucketWebsite",
                "s3:GetBucketVersioning",
                "s3:GetBucketTagging",
                "s3:GetBucketRequestPayment",
                "s3:GetBucketPolicy",
                "s3:GetBucketObjectLockConfiguration",
                "s3:GetBucketLogging",
                "s3:GetBucketLocation",
                "s3:GetBucketCORS",
                "s3:GetAccelerateConfiguration",
                "s3:CreateBucket"
            ],
            "Resource": [
                "arn:aws:s3:::mantil-*-n3isbby/*",
                "arn:aws:s3:::mantil-*-n3isbby"
            ]
        },
        {
            "Sid": "",
            "Effect": "Allow",
            "Action": [
                "dynamodb:TagResource",
                "dynamodb:ListTagsOfResource",
                "dynamodb:DescribeTimeToLive",
                "dynamodb:DescribeTable",
                "dynamodb:DescribeContinuousBackups",
                "dynamodb:CreateTable"
            ],
            "Resource": "arn:aws:dynamodb:*:*:table/*-n3isbby"
        }
    ]
}
IvanVlasic commented 2 years ago

Permissionsi za destroy:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "",
            "Effect": "Allow",
            "Action": [
                "apigateway:PUT",
                "apigateway:POST",
                "apigateway:PATCH",
                "apigateway:GET",
                "apigateway:DELETE"
            ],
            "Resource": "*"
        },
        {
            "Sid": "",
            "Effect": "Allow",
            "Action": [
                "lambda:RemovePermission",
                "lambda:ListVersionsByFunction",
                "lambda:GetPolicy",
                "lambda:GetFunctionCodeSigningConfig",
                "lambda:GetFunction",
                "lambda:DeleteFunction"
            ],
            "Resource": "arn:aws:lambda:*:*:function:*-nbiissi"
        },
        {
            "Sid": "",
            "Effect": "Allow",
            "Action": [
                "logs:PutLogEvents",
                "logs:ListTagsLogGroup",
                "logs:DeleteLogGroup",
                "logs:CreateLogStream"
            ],
            "Resource": [
                "arn:aws:logs:*:*:log-group:*-nbiissi:log-stream:*",
                "arn:aws:logs:*:*:log-group:*-nbiissi"
            ]
        },
        {
            "Sid": "",
            "Effect": "Allow",
            "Action": [
                "logs:ListLogDeliveries",
                "logs:DescribeLogGroups",
                "logs:DeleteLogDelivery"
            ],
            "Resource": "*"
        },
        {
            "Sid": "",
            "Effect": "Allow",
            "Action": [
                "iam:ListRolePolicies",
                "iam:ListInstanceProfilesForRole",
                "iam:ListAttachedRolePolicies",
                "iam:GetRolePolicy",
                "iam:GetRole",
                "iam:DeleteRolePolicy",
                "iam:DeleteRole"
            ],
            "Resource": "arn:aws:iam::*:role/*-nbiissi"
        },
        {
            "Sid": "",
            "Effect": "Allow",
            "Action": [
                "s3:PutObject",
                "s3:ListBucket",
                "s3:GetReplicationConfiguration",
                "s3:GetObject",
                "s3:GetLifecycleConfiguration",
                "s3:GetEncryptionConfiguration",
                "s3:GetBucketWebsite",
                "s3:GetBucketVersioning",
                "s3:GetBucketTagging",
                "s3:GetBucketRequestPayment",
                "s3:GetBucketPolicy",
                "s3:GetBucketObjectLockConfiguration",
                "s3:GetBucketLogging",
                "s3:GetBucketLocation",
                "s3:GetBucketCORS",
                "s3:GetAccelerateConfiguration",
                "s3:DeleteObjectVersion",
                "s3:DeleteObject",
                "s3:DeleteBucketPolicy",
                "s3:DeleteBucket"
            ],
            "Resource": [
                "arn:aws:s3:::mantil-*-nbiissi/*",
                "arn:aws:s3:::mantil-*-nbiissi"
            ]
        },
        {
            "Sid": "",
            "Effect": "Allow",
            "Action": [
                "dynamodb:ListTagsOfResource",
                "dynamodb:DescribeTimeToLive",
                "dynamodb:DescribeTable",
                "dynamodb:DescribeContinuousBackups",
                "dynamodb:DeleteTable"
            ],
            "Resource": "arn:aws:dynamodb:*:*:table/*-nbiissi"
        },
        {
            "Sid": "",
            "Effect": "Allow",
            "Action": "tag:GetResources",
            "Resource": "*"
        }
    ]
}
IvanVlasic commented 2 years ago

I evo na kraju i setup:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Action": [
                "apigateway:GET",
                "apigateway:POST",
                "apigateway:PATCH",
                "apigateway:DELETE",
                "apigateway:PUT",
                "apigateway:TagResource"
            ],
            "Resource": [
                "*"
            ],
            "Effect": "Allow"
        },
        {
            "Action": [
                "s3:GetObject"
            ],
            "Resource": [
                "arn:aws:s3:::mantil-releases*/*"
            ],
            "Effect": "Allow"
        },
        {
            "Action": [
                "lambda:CreateFunction",
                "lambda:AddPermission",
                "lambda:ListVersionsByFunction",
                "lambda:GetFunction",
                "lambda:GetFunctionCodeSigningConfig",
                "lambda:GetPolicy",
                "lambda:DeleteFunction",
                "lambda:RemovePermission",
                "lambda:GetLayerVersion"
            ],
            "Resource": [
                "arn:aws:lambda:*:*:function:mantil-*-zc2ucsa",
                "arn:aws:lambda:*:*:layer:*:*"
            ],
            "Effect": "Allow"
        },
        {
            "Action": [
                "iam:GetRole"
            ],
            "Resource": [
                "arn:aws:iam::*:role/*"
            ],
            "Effect": "Allow"
        },
        {
            "Action": [
                "iam:GetRolePolicy",
                "iam:ListAttachedRolePolicies",
                "iam:CreateRole",
                "iam:ListRolePolicies",
                "iam:PutRolePolicy",
                "iam:DeleteRolePolicy",
                "iam:DeleteRole",
                "iam:ListInstanceProfilesForRole",
                "iam:TagRole",
                "iam:PassRole"
            ],
            "Resource": [
                "arn:aws:iam::*:role/mantil-*-zc2ucsa",
                "arn:aws:iam::*:role/APIGatewayPushToCloudWatchLogsRole"
            ],
            "Effect": "Allow"
        },
        {
            "Action": [
                "s3:CreateBucket",
                "s3:PutBucketTagging",
                "s3:PutLifecycleConfiguration",
                "s3:DeleteBucket",
                "s3:ListBucket",
                "s3:PutObject",
                "s3:GetObject",
                "s3:DeleteObject",
                "s3:DeleteObjectVersion"
            ],
            "Resource": [
                "arn:aws:s3:::mantil-*-zc2ucsa",
                "arn:aws:s3:::mantil-*-zc2ucsa/*"
            ],
            "Effect": "Allow"
        },
        {
            "Action": [
                "logs:CreateLogStream",
                "logs:PutLogEvents",
                "logs:DeleteLogGroup",
                "logs:ListTagsLogGroup"
            ],
            "Resource": [
                "arn:aws:logs:*:*:log-group:*-zc2ucsa",
                "arn:aws:logs:*:*:log-group:*-zc2ucsa:log-stream:*"
            ],
            "Effect": "Allow"
        },
        {
            "Action": [
                "logs:PutResourcePolicy",
                "logs:DescribeResourcePolicies",
                "logs:PutRetentionPolicy",
                "logs:CreateLogGroup",
                "logs:DescribeLogGroups",
                "logs:GetLogDelivery",
                "logs:CreateLogDelivery",
                "logs:UpdateLogDelivery",
                "logs:ListLogDeliveries",
                "logs:DeleteLogDelivery"
            ],
            "Resource": [
                "*"
            ],
            "Effect": "Allow"
        }
    ]
}

S time sam zavrsio sve lambde. Sad samo moramo pripaziti kada nesto mjenjamo da promjene uskladimo sa permissionima.