diff --git a/knowledge base/cloud computing/aws/iam.md b/knowledge base/cloud computing/aws/iam.md
index bd7b684..369804f 100644
--- a/knowledge base/cloud computing/aws/iam.md
+++ b/knowledge base/cloud computing/aws/iam.md
@@ -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.
+Represent human users or workloads needing to interact with AWS resources.
Consist of a name and credentials.
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.
+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.
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.
+ As in, **at least one** statement must allow access to a set of resources.
+- **Conditions** in a Statement operate in an `AND` fashion.
+ As in, **all** conditions must resolve true for the statement to allow access.
+- **Operator values** in a Condition operate in an `OR` fashion.
+ 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.
-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].
-
+
```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.
-
+
```json
{
@@ -338,13 +348,32 @@ Add the `"Bool": {"aws:MultiFactorAuthPresent": true}` condition to the Role's T
-When requiring MFA with AssumeRole, identities need to pass values for the SerialNumber and TokenCode parameters.
-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.
+`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.
+
-
+```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
+```
+
+
+
+For CLI access, users will **need** to add the `mfa_serial` setting to their profile.
+
+
```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
[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
diff --git a/knowledge base/pulumi.md b/knowledge base/pulumi.md
index 7666522..359122d 100644
--- a/knowledge base/pulumi.md
+++ b/knowledge base/pulumi.md
@@ -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.
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.
+1. Declare the types of resources one wants to export from the class.
+
+
+
+ ```ts
+ class StandardAwsVpc extends pulumi.ComponentResource {
+ internetGateway: aws.ec2.InternetGateway
+ vpc: aws.ec2.Vpc
+ };
+ ```
+
+
+
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`.
-
+
```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.
- Sample code
+ Example: standardized AWS VPC
+
+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(
+
+ Example: standardized AWS service role
+
+```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));
+```
+
+
+
## 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]
[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/
diff --git a/snippets/aws/cli.fish b/snippets/aws/cli.fish
index bf0384e..7722312 100644
--- a/snippets/aws/cli.fish
+++ b/snippets/aws/cli.fish
@@ -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
diff --git a/snippets/pulumi/commands.fish b/snippets/pulumi/commands.fish
index 4613052..c2b0aa0 100644
--- a/snippets/pulumi/commands.fish
+++ b/snippets/pulumi/commands.fish
@@ -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