mirror of
https://gitea.com/mcereda/oam.git
synced 2026-02-09 05:44:23 +00:00
chore(pulumi/components): add standardized aws service account example
This commit is contained in:
@@ -65,13 +65,15 @@ Refer [aws.permissions.cloud] for a community-driven source of truth for AWS IAM
|
||||
|
||||
## Users
|
||||
|
||||
Refer [IAM users].
|
||||
Refer [IAM Users].
|
||||
|
||||
Represent a human user or workload needing to interact with AWS resources.<br/>
|
||||
Represent human users or workloads needing to interact with AWS resources.<br/>
|
||||
Consist of a name and credentials.<br/>
|
||||
Applications using their credentials to make requests are typically referred to as _service accounts_.
|
||||
|
||||
IAM Users with administrator permissions are **not** the same thing as the AWS account's root user.
|
||||
IAM Users with administrator permissions are **not** the same thing as the AWS Account's root user.<br/>
|
||||
The root user is **required** to perform some [specific tasks][tasks that require root user credentials] on the account,
|
||||
which will **not** be available if signed in as any other user.
|
||||
|
||||
IAM identifies IAM Users via:
|
||||
|
||||
@@ -140,7 +142,16 @@ Their _effect_ can be to `allow` or `deny` such actions. A `deny` statement **al
|
||||
Mostly stored as structured JSON documents.<br/>
|
||||
Each Policy comes with one or several _statements_. Each statement defines an effect.
|
||||
|
||||
IAM does not expose Policies' `Sid` element in the IAM API, so it can't be used to retrieve statements.
|
||||
IAM does **not** expose Policies' `Sid` element in the IAM API, so it **cannot** be used to filter retrieved statements.
|
||||
|
||||
Logical evaluation:
|
||||
|
||||
- **Statements** in a Policy operate in an `OR` fashion.<br/>
|
||||
As in, **at least one** statement must allow access to a set of resources.
|
||||
- **Conditions** in a Statement operate in an `AND` fashion.<br/>
|
||||
As in, **all** conditions must resolve true for the statement to allow access.
|
||||
- **Operator values** in a Condition operate in an `OR` fashion.<br/>
|
||||
As in, **at least one** value must match for a Condition to resolve true.
|
||||
|
||||
Policy examples:
|
||||
|
||||
@@ -202,7 +213,7 @@ Policy examples:
|
||||
### Trust Policies
|
||||
|
||||
Specific type of resource-based policy for IAM roles.<br/>
|
||||
Used to allow Principals ans AWS Services to assume Roles.
|
||||
Used to allow Principals and other AWS Services to assume Roles.
|
||||
|
||||
### Trust Relationships
|
||||
|
||||
@@ -245,7 +256,6 @@ Principals and AWS Services can assume Roles as long as:
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [
|
||||
{
|
||||
"Sid": "AllowMeToAssumeThoseRoles",
|
||||
"Effect": "Allow",
|
||||
"Action": "sts:AssumeRole",
|
||||
"Resource": [
|
||||
@@ -287,7 +297,7 @@ Principals and AWS Services can assume Roles as long as:
|
||||
|
||||
Allowed entities can assume Roles using the [STS AssumeRole API][assumerole api reference].
|
||||
|
||||
<details style="margin-top: -1em; padding-bottom: 1em;">
|
||||
<details style="margin: -1rem 0 1rem 1rem">
|
||||
|
||||
```sh
|
||||
$ aws sts assume-role --role-arn "arn:aws:iam::012345678901:role/EksAdminRole" \
|
||||
@@ -316,7 +326,7 @@ Refer [Using AWS CLI Securely with IAM Roles and MFA].
|
||||
|
||||
Add the `"Bool": {"aws:MultiFactorAuthPresent": true}` condition to the Role's Trust Relationships.
|
||||
|
||||
<details style="margin-top: -1em; padding-bottom: 1em;">
|
||||
<details style="margin: -1rem 0 1rem 1rem">
|
||||
|
||||
```json
|
||||
{
|
||||
@@ -338,13 +348,32 @@ Add the `"Bool": {"aws:MultiFactorAuthPresent": true}` condition to the Role's T
|
||||
|
||||
</details>
|
||||
|
||||
When requiring MFA with AssumeRole, identities need to pass values for the SerialNumber and TokenCode parameters.<br/>
|
||||
SerialNumbers identify the users' hardware or virtual MFA devices, TokenCodes are the time-based one-time password
|
||||
(TOTP) value that devices produce.
|
||||
When requiring MFA with AssumeRole, identities **must** pass values for the `SerialNumber` and `TokenCode`
|
||||
parameters.<br/>
|
||||
`SerialNumber`s identify the users' hardware or virtual MFA devices, while `TokenCode`s are the time-based one-time
|
||||
password (TOTP) value that devices produce.
|
||||
|
||||
For CLI access, the user will need to add the `mfa_serial` setting to their profile.
|
||||
<details style="margin: -1rem 0 1rem 1rem">
|
||||
|
||||
<details style="margin-top: -1em; padding-bottom: 1em;">
|
||||
```sh
|
||||
$ aws sts assume-role --output 'yaml' --duration-seconds '900' \
|
||||
--role-arn 'arn:aws:iam::012345678901:role/EksAdminRole' --role-session-name 'lookAt-him-heIsThe-EksAdmin-now' \
|
||||
--serial-number 'arn:aws:iam::012345678901:mfa/gopass' --token-code '123456'
|
||||
AssumedRoleUser:
|
||||
Arn: arn:aws:sts::012345678901:assumed-role/EksAdminRole/lookAt-him-heIsThe-EksAdmin-now
|
||||
AssumedRoleId: AROA2HKHF74L72AABBCCDD:lookAt-him-heIsThe-EksAdmin-now
|
||||
Credentials:
|
||||
AccessKeyId: ASIA2HKHF74L7YOAUZHR
|
||||
Expiration: '2025-04-12T08:09:46+00:00'
|
||||
SecretAccessKey: ErhyPKjQkI3GbrnszpOvMTi8AvmziGbSIOIcNS9k
|
||||
SessionToken: IQoJb3JpZ2…LxEOLkm9U
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
For CLI access, users will **need** to add the `mfa_serial` setting to their profile.
|
||||
|
||||
<details style="margin: -1rem 0 1rem 1rem">
|
||||
|
||||
```ini
|
||||
[default]
|
||||
@@ -372,6 +401,7 @@ UserId: AROA2HKHF74L72AABBCCDD:botocore-session-1234567890
|
||||
- [aws.permissions.cloud]
|
||||
- [Using service-linked roles]
|
||||
- [IAM and AWS STS quotas]
|
||||
- [AWS global condition context keys]
|
||||
|
||||
### Sources
|
||||
|
||||
@@ -412,6 +442,7 @@ UserId: AROA2HKHF74L72AABBCCDD:botocore-session-1234567890
|
||||
<!-- Files -->
|
||||
<!-- Upstream -->
|
||||
[assumerole api reference]: https://docs.aws.amazon.com/STS/latest/APIReference/API_AssumeRole.html
|
||||
[aws global condition context keys]: https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_condition-keys.html
|
||||
[can i increase the duration of the iam role chaining session?]: https://repost.aws/knowledge-center/iam-role-chaining-limit
|
||||
[creating a role to delegate permissions to an iam user]: https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_create_for-user.html
|
||||
[how can i monitor the account activity of specific iam users, roles, and aws access keys?]: https://repost.aws/knowledge-center/view-iam-history
|
||||
@@ -423,6 +454,7 @@ UserId: AROA2HKHF74L72AABBCCDD:botocore-session-1234567890
|
||||
[iam user groups]: https://docs.aws.amazon.com/IAM/latest/UserGuide/id_groups.html
|
||||
[iam users]: https://docs.aws.amazon.com/IAM/latest/UserGuide/id_users.html
|
||||
[not authorized to perform: sts:assumerole]: https://repost.aws/questions/QUOY5XngCtRyOX4Desaygz8Q/not-authorized-to-perform-sts-assumerole
|
||||
[tasks that require root user credentials]: https://docs.aws.amazon.com/IAM/latest/UserGuide/id_root-user.html#root-user-tasks
|
||||
[troubleshooting iam roles]: https://docs.aws.amazon.com/IAM/latest/UserGuide/troubleshoot_roles.html
|
||||
[use an iam role in the aws cli]: https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-role.html
|
||||
[using iam policy conditions for fine-grained access control to manage resource record sets]: https://docs.aws.amazon.com/Route53/latest/DeveloperGuide/specifying-rrset-conditions.html
|
||||
|
||||
@@ -857,7 +857,7 @@ backend:
|
||||
|
||||
FIXME: should this be under [Program]?
|
||||
|
||||
Refer [Component resources].
|
||||
Refer [Component resources] and [Create a ComponentResource].
|
||||
|
||||
Logical grouping of resources.<br/>
|
||||
Usually leveraged to instantiate a set of related resources, aggregate them as children, and create larger abstractions
|
||||
@@ -882,6 +882,19 @@ Refer [Pulumi Crosswalk for AWS] or [Google Cloud Static Website] as examples.
|
||||
|
||||
</details>
|
||||
|
||||
1. Declare the types of resources one wants to export from the class.
|
||||
|
||||
<details style="padding: 0 0 1rem 1rem">
|
||||
|
||||
```ts
|
||||
class StandardAwsVpc extends pulumi.ComponentResource {
|
||||
internetGateway: aws.ec2.InternetGateway
|
||||
vpc: aws.ec2.Vpc
|
||||
};
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
1. Inside its constructor, chain to the base constructor and pass it the subclass' name, arguments, and options.
|
||||
|
||||
Upon creation of a new instance of the Component, the call to the base constructor registers the instance with the
|
||||
@@ -892,10 +905,12 @@ Refer [Pulumi Crosswalk for AWS] or [Google Cloud Static Website] as examples.
|
||||
Components must also register a unique _type name_ with the base constructor. These names are namespaced alongside
|
||||
non-Component resources such as `aws:lambda:Function`.
|
||||
|
||||
<details style="padding: 0 0 1em 1em">
|
||||
<details style="padding: 0 0 1rem 1rem">
|
||||
|
||||
```ts
|
||||
class StandardAwsVpc extends pulumi.ComponentResource {
|
||||
…
|
||||
|
||||
constructor(name: string, args: pulumi.Inputs, opts?: pulumi.ComponentResourceOptions) {
|
||||
super("exampleOrg:StandardAwsVpc", name, {}, opts);
|
||||
};
|
||||
@@ -911,15 +926,17 @@ Refer [Pulumi Crosswalk for AWS] or [Google Cloud Static Website] as examples.
|
||||
|
||||
```ts
|
||||
class StandardAwsVpc extends pulumi.ComponentResource {
|
||||
…
|
||||
|
||||
constructor(name: string, args: pulumi.Inputs, opts?: pulumi.ComponentResourceOptions) {
|
||||
…
|
||||
|
||||
const vpc = new aws.ec2.Vpc(
|
||||
this.vpc = new aws.ec2.Vpc(
|
||||
`${name}`,
|
||||
{ … },
|
||||
{ parent: this },
|
||||
);
|
||||
const internetGateway = new aws.ec2.InternetGateway(
|
||||
this.internetGateway = new aws.ec2.InternetGateway(
|
||||
`${name}`,
|
||||
{
|
||||
vpcId: vpc.id,
|
||||
@@ -946,7 +963,7 @@ Refer [Pulumi Crosswalk for AWS] or [Google Cloud Static Website] as examples.
|
||||
…
|
||||
|
||||
this.registerOutputs({
|
||||
vpcId: vpc.id,
|
||||
vpcId: this.vpc.id,
|
||||
});
|
||||
};
|
||||
};
|
||||
@@ -972,16 +989,21 @@ Refer [Pulumi Crosswalk for AWS] or [Google Cloud Static Website] as examples.
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>Sample code</summary>
|
||||
<summary>Example: standardized AWS VPC</summary>
|
||||
|
||||
FIXME: check
|
||||
|
||||
```ts
|
||||
import * as aws from "@pulumi/aws";
|
||||
|
||||
export class StandardAwsVpc extends pulumi.ComponentResource {
|
||||
internetGateway: aws.ec2.InternetGateway
|
||||
vpc: aws.ec2.Vpc
|
||||
|
||||
constructor(name: string, args: pulumi.Inputs, opts?: pulumi.ComponentResourceOptions) {
|
||||
super("exampleOrg:StandardAwsVpc", name, {}, opts);
|
||||
|
||||
const vpc = new aws.ec2.Vpc(
|
||||
this.vpc = new aws.ec2.Vpc(
|
||||
`${name}`,
|
||||
{
|
||||
tags: {
|
||||
@@ -994,7 +1016,7 @@ export class StandardAwsVpc extends pulumi.ComponentResource {
|
||||
},
|
||||
{ parent: this },
|
||||
);
|
||||
const internetGateway = new aws.ec2.InternetGateway(
|
||||
this.internetGateway = new aws.ec2.InternetGateway(
|
||||
name,
|
||||
{
|
||||
tags: {
|
||||
@@ -1002,14 +1024,14 @@ export class StandardAwsVpc extends pulumi.ComponentResource {
|
||||
...args.tags,
|
||||
},
|
||||
|
||||
vpcId: vpc.id,
|
||||
vpcId: this.vpc.id,
|
||||
},
|
||||
{ parent: vpc },
|
||||
{ parent: this.vpc },
|
||||
);
|
||||
…
|
||||
|
||||
this.registerOutputs({
|
||||
vpcId: vpc.id,
|
||||
vpcId: this.vpc.id,
|
||||
});
|
||||
};
|
||||
};
|
||||
@@ -1029,6 +1051,93 @@ const currentVpc = new StandardAwsVpc(
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>Example: standardized AWS service role</summary>
|
||||
|
||||
```ts
|
||||
import * as pulumi from '@pulumi/pulumi';
|
||||
import * as aws from '@pulumi/aws';
|
||||
|
||||
class StandardServiceRole extends pulumi.ComponentResource {
|
||||
assumeRole: {
|
||||
iamPolicy: aws.iam.Policy
|
||||
}
|
||||
iamRole: aws.iam.Role
|
||||
|
||||
constructor(
|
||||
name: string,
|
||||
args: aws.iam.RoleArgs,
|
||||
opts?: pulumi.ComponentResourceOptions,
|
||||
) {
|
||||
super('exampleOrg:StandardServiceRole', name, {}, opts);
|
||||
|
||||
this.iamRole = new aws.iam.Role(
|
||||
name,
|
||||
{
|
||||
...args,
|
||||
tags: {
|
||||
ServiceRole: 'true',
|
||||
StandardResource: 'true',
|
||||
...args.tags,
|
||||
},
|
||||
},
|
||||
{ parent: this },
|
||||
);
|
||||
|
||||
this.assumeRole = {
|
||||
iamPolicy: new aws.iam.Policy(
|
||||
`${name}-assumeRole`,
|
||||
{
|
||||
name: `${args.name}-AssumeRole`,
|
||||
description: `Allows bearers to try and assume the ${args.name} standard service role`,
|
||||
tags: {
|
||||
StandardResource: 'true',
|
||||
},
|
||||
|
||||
policy: pulumi.jsonStringify({
|
||||
Version: '2012-10-17',
|
||||
Statement: [{
|
||||
Sid: `AllowAssumingThe${args.name}Role`,
|
||||
Effect: 'Allow',
|
||||
Action: 'sts:AssumeRole',
|
||||
Resource: this.iamRole.arn,
|
||||
}],
|
||||
}),
|
||||
},
|
||||
{ parent: this },
|
||||
),
|
||||
};
|
||||
|
||||
this.registerOutputs({
|
||||
iamRole: this.iamRole,
|
||||
assumeRole: this.assumeRole,
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
const serviceRole = new StandardServiceRole(
|
||||
'someServiceRole',
|
||||
{
|
||||
name: 'SomeServiceRole',
|
||||
description: 'SomeServiceRole',
|
||||
|
||||
assumeRolePolicy: pulumi.jsonStringify({
|
||||
Version: '2012-10-17',
|
||||
Statement: [{
|
||||
Effect: 'Allow',
|
||||
Principal: {
|
||||
AWS: '012345678901',
|
||||
},
|
||||
Action: 'sts:AssumeRole',
|
||||
}],
|
||||
}),
|
||||
},
|
||||
);
|
||||
serviceRole.assumeRole.iamPolicy.name.apply(policyName => console.log(policyName));
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
## Import resources
|
||||
|
||||
FIXME: should this be under [Program] or [Stack]?
|
||||
@@ -1297,6 +1406,7 @@ Solution: follow the suggestion in the warning message:
|
||||
- [`pulumi config set-all`][pulumi config set-all]
|
||||
- [Importing resources]
|
||||
- [Property paths]
|
||||
- [Create a ComponentResource]
|
||||
|
||||
<!--
|
||||
Reference
|
||||
@@ -1351,5 +1461,6 @@ Solution: follow the suggestion in the warning message:
|
||||
|
||||
<!-- Others -->
|
||||
[assigning tags by default on aws with pulumi]: https://blog.scottlowe.org/2023/09/11/assigning-tags-by-default-on-aws-with-pulumi/
|
||||
[create a componentresource]: https://pulumi.awsworkshop.io/30_modern_iac_ts/45_componens/10_create_component.html
|
||||
[docker images]: https://hub.docker.com/u/pulumi
|
||||
[things i wish i knew earlier about pulumi]: https://vsupalov.com/pulumi-learnings/
|
||||
|
||||
@@ -23,6 +23,9 @@ aws --profile 'engineer' sts assume-role \
|
||||
aws sts get-caller-identity
|
||||
AWS_PROFILE='engineer' aws sts get-caller-identity
|
||||
|
||||
# Clear cached credentials
|
||||
rm -r ~'/.aws/cli/cache'
|
||||
|
||||
|
||||
# Run as Docker container
|
||||
docker run --rm -ti 'amazon/aws-cli' --version
|
||||
|
||||
@@ -38,6 +38,7 @@ pulumi config set 'boincAcctMgrUrl' 'https://bam.boincstats.com'
|
||||
pulumi config set --secret 'boincGuiRpcPasswd' 'something-something-darkside'
|
||||
pulumi config set --path 'outer.inner' 'value'
|
||||
pulumi config set --path 'list[1]' 'value'
|
||||
gpg --export 'smth@example.org' | pulumi config set 'smthTeam:pgpKey-public-raw' --type 'string'
|
||||
|
||||
# Gitlab provider
|
||||
# 'baseUrl' requires the ending slash
|
||||
@@ -78,6 +79,9 @@ pulumi stack export | jq -r '.deployment.resources[]|{"urn":.urn,"provider":.pro
|
||||
# Check providers are all of a specific version
|
||||
pulumi stack export | jq -r '.deployment.resources[].provider' | grep -v 'aws::default_6_50_0'
|
||||
|
||||
# Get the AWS secret access key of an aws.iam.AccessKey resource
|
||||
pulumi stack output 'someAccessKey' | jq -r '.encryptedSecret' - | base64 -d | gpg --decrypt
|
||||
|
||||
# Avoid permission errors when deleting clusters with charts and stuff.
|
||||
PULUMI_K8S_DELETE_UNREACHABLE='true' pulumi destroy
|
||||
|
||||
|
||||
Reference in New Issue
Block a user