Cloud fundamentals all 3 written
IaaS, PaaS, SaaS and FaaS; regions and blast radius; the Shared Responsibility Model. Vendor-neutral, before any one vendor.
15 IaaS, PaaS, SaaS, FaaS: what you manage vs what they manage
Every layer of a running system -- hardware, virtualization, OS,
runtime, application code, data -- has to be managed by someone. IaaS, PaaS, SaaS and FaaS
are not four different technologies; they are four different places to draw the same
line. Moving up the list trades control for less operational work, and neither direction
is "better" -- it is a decision about which parts of the stack your team wants to own.
The same layers, four different lines
IaaS Infrastructure as a Service
You get a virtual machine. Everything above the hypervisor is
yours.
- Provider manages: physical hardware, the hypervisor, the network fabric
- You manage: the OS, patching, the runtime, the application, scaling it yourself
- Example: an EC2 instance
PaaS Platform as a Service
You get a place to put code. The OS and runtime are the
provider's problem.
- Provider manages: OS, patching, the runtime, autoscaling infrastructure
- You manage: your application code, its configuration, its data
- Example: AWS Elastic Beanstalk, Heroku
SaaS Software as a Service
You get the finished application. Nothing below the login
screen is yours.
- Provider manages: everything -- infrastructure, runtime, and the application
itself
- You manage: your own data and configuration inside it
- Example: Gmail, Salesforce, GitHub itself
FaaS Functions as a Service
You get to run one function, on demand. No server, ever, is
visible to you.
- Provider manages: everything IaaS and PaaS cover, plus starting and stopping
your code per request
- You manage: one function's code, and what it is triggered by
- Example: AWS Lambda -- covered properly in Part 8
Drawing part of the line with a real command, not a diagram
"Who manages the OS" sounds abstract until you actually query a real IaaS resource and
see that the OS is a choice you made, not a given -- and that nothing about the service
tells the provider what is running inside it.
IaaS: you chose the OS image, so patching it is your job
ran at build time
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16# AWS_ENDPOINT_URL is already set, pointing at this build's own moto instance --
# every aws command below is real aws CLI, talking to a real (local, fake) AWS.
echo "an IaaS resource: a real EC2 instance, launched against a chosen AMI (a specific OS image):"
instance=$(aws ec2 run-instances --image-id ami-03cf127a \
--instance-type t2.micro --count 1 --output json)
instance_id=$(echo "$instance" | grep -o '"InstanceId": "[^"]*"' | head -1 | cut -d'"' -f4)
echo "launched: $instance_id"
echo
echo "what AWS itself reports for it -- it knows the AMI ID, NOT what OS is inside it:"
aws ec2 describe-instances --instance-ids "$instance_id" \
--query 'Reservations[0].Instances[0].{ImageId:ImageId,InstanceType:InstanceType,State:State.Name}' \
--output json
check "an EC2 instance really was created" "$([ -n "$instance_id" ] && echo yes)" "yes"
check "the instance ID has the real AWS i-xxxx shape" "$(echo "$instance_id" | grep -Ec '^i-[0-9a-f]+$')" "1"
What it printed, when the build ran it
an IaaS resource: a real EC2 instance, launched against a chosen AMI (a specific OS image):
launched: i-19cb0e5afd8ef103f
what AWS itself reports for it -- it knows the AMI ID, NOT what OS is inside it:
{
"ImageId": "ami-03cf127a",
"InstanceType": "t2.micro",
"State": "running"
}
ok an EC2 instance really was created
ok the instance ID has the real AWS i-xxxx shape
What that command just proved. AWS's own API answer for the instance
contains an image ID and an instance type -- infrastructure facts -- and nothing about
what is running inside it, because AWS genuinely does not manage that. If that instance's
OS has an unpatched vulnerability next month, that is not a ticket you can raise with AWS
support; it is EC2's whole business model, working exactly as designed.
Contrasting with a service where that question does not even apply
S3 is not IaaS. There is no instance to patch, no OS to choose, because there is no
virtual machine anywhere in what you are renting -- you are renting storage, addressed by a
key, and the "server" question is meaningless for it in a way it is not for EC2.
Where the IaaS question ('which OS') stops making sense at all
ran at build time
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17aws s3 mb s3://course-service-model-bucket > /dev/null
echo "hello" | aws s3 cp - s3://course-service-model-bucket/file.txt > /dev/null
echo "asking S3 for anything resembling 'what OS, what instance type' about this bucket:"
aws s3api get-bucket-location --bucket course-service-model-bucket
echo
echo "there is no 'instance-type' equivalent for a bucket at all -- the question genuinely"
echo "does not apply, because there is no server-shaped thing being rented here."
readback=$(aws s3 cp s3://course-service-model-bucket/file.txt -)
echo
echo "the object still round-trips correctly, with no server ever named or chosen:"
echo "$readback"
check "the object comes back exactly as written, through pure storage, not a machine" \
"$readback" "hello"
What it printed, when the build ran it
asking S3 for anything resembling 'what OS, what instance type' about this bucket:
{
"LocationConstraint": null
}
there is no 'instance-type' equivalent for a bucket at all -- the question genuinely
does not apply, because there is no server-shaped thing being rented here.
the object still round-trips correctly, with no server ever named or chosen:
hello
ok the object comes back exactly as written, through pure storage, not a machine
Choosing a model is choosing what you want to be paged about
- IaaS: paged for OS-level issues -- disk full, kernel panic, an
unpatched CVE in a library you installed.
- PaaS: paged for application-level issues only -- the platform
itself failing is the provider's incident, not yours.
- SaaS: never paged for the service itself; only for your own
configuration or data inside it.
- FaaS: paged for your function's logic and its triggers, and for
nothing resembling "the server," because there genuinely is no persistent one from your
side of the API.
This is the practical test for "which model is this, really": read the responsibilities
in a real incident, not the marketing name of the product.
16 Regions, Availability Zones and blast radius
A region is a real geographic area (Ireland, Ohio, Singapore). An
Availability Zone is one or more physically separate data centres inside that region, with
independent power and networking, close enough for low-latency replication between them
but far enough apart that one burning down does not take out the others. Both of those
facts are queryable, not just asserted -- this lesson queries them.
The real list, from AWS's own API
Every region and every AZ used anywhere in this course so far is a real entry in AWS's
actual, current list -- fetched here, not typed from memory.
Real regions and Availability Zones, queried directly
ran at build time
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16echo "a sample of AWS's actual current regions:"
aws ec2 describe-regions --query 'Regions[].RegionName' --output text | tr '\t' '\n' | sort | head -8
region_count=$(aws ec2 describe-regions --query 'length(Regions)' --output text)
echo
echo "total regions AWS reports right now: $region_count"
echo
echo "the real Availability Zones inside us-east-1:"
aws ec2 describe-availability-zones --region us-east-1 \
--query 'AvailabilityZones[].ZoneName' --output text | tr '\t' '\n'
az_count=$(aws ec2 describe-availability-zones --region us-east-1 --query 'length(AvailabilityZones)' --output text)
check "AWS reports more than a handful of regions" "$([ "$region_count" -gt 10 ] && echo yes)" "yes"
check "us-east-1 alone has multiple real, distinct AZs" "$([ "$az_count" -ge 3 ] && echo yes)" "yes"
What it printed, when the build ran it
a sample of AWS's actual current regions:
af-south-1
ap-east-1
ap-east-2
ap-northeast-1
ap-northeast-2
ap-northeast-3
ap-south-1
ap-south-2
total regions AWS reports right now: 38
the real Availability Zones inside us-east-1:
us-east-1a
us-east-1b
us-east-1c
us-east-1d
us-east-1e
us-east-1f
ok AWS reports more than a handful of regions
ok us-east-1 alone has multiple real, distinct AZs
Blast radius: what "only in one AZ" actually costs you
Launch a resource without specifying a zone, and the provider picks one for you --
silently making a single-AZ decision on your behalf unless you actively spread things out.
The panel below launches two EC2 instances the naive way and shows they can land in the
same zone purely by default behaviour.
Launching without choosing a zone: the provider decides for you
ran at build time
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21instance_a=$(aws ec2 run-instances --image-id ami-03cf127a --instance-type t2.micro --count 1 --output json)
instance_b=$(aws ec2 run-instances --image-id ami-03cf127a --instance-type t2.micro --count 1 --output json)
id_a=$(echo "$instance_a" | grep -o '"InstanceId": "[^"]*"' | head -1 | cut -d'"' -f4)
id_b=$(echo "$instance_b" | grep -o '"InstanceId": "[^"]*"' | head -1 | cut -d'"' -f4)
az_a=$(aws ec2 describe-instances --instance-ids "$id_a" \
--query 'Reservations[0].Instances[0].Placement.AvailabilityZone' --output text)
az_b=$(aws ec2 describe-instances --instance-ids "$id_b" \
--query 'Reservations[0].Instances[0].Placement.AvailabilityZone' --output text)
echo "instance A landed in: $az_a"
echo "instance B landed in: $az_b"
echo
echo "neither launch specified a zone -- whatever AZ they land in is whatever the"
echo "provider's default placement decided, not a deliberate choice either way."
check "both instances really were created" \
"$([ -n "$id_a" ] && [ -n "$id_b" ] && echo yes)" "yes"
check "each instance was actually placed in a real, named AZ" \
"$(echo "$az_a $az_b" | grep -Ec '^[a-z]+-[a-z]+-[0-9][a-z] [a-z]+-[a-z]+-[0-9][a-z]$')" "1"
What it printed, when the build ran it
instance A landed in: us-east-1a
instance B landed in: us-east-1a
neither launch specified a zone -- whatever AZ they land in is whatever the
provider's default placement decided, not a deliberate choice either way.
ok both instances really were created
ok each instance was actually placed in a real, named AZ
Spreading deliberately across zones -- the actual fix
Naming the AvailabilityZone explicitly on each launch is the whole
mechanism. There is no separate "high availability" flag; it is just placing resources in
different real zones on purpose, so no single data centre failure takes everything down at
once.
Choosing distinct AZs on purpose, and confirming the placement stuck
ran at build time
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29zones=$(aws ec2 describe-availability-zones --region us-east-1 --query 'AvailabilityZones[].ZoneName' --output text)
zone_array=($zones)
zone1="${zone_array[0]}"
zone2="${zone_array[1]}"
echo "deliberately placing one instance in $zone1 and another in $zone2:"
deliberate_a=$(aws ec2 run-instances --image-id ami-03cf127a --instance-type t2.micro \
--count 1 --placement AvailabilityZone="$zone1" --output json)
deliberate_b=$(aws ec2 run-instances --image-id ami-03cf127a --instance-type t2.micro \
--count 1 --placement AvailabilityZone="$zone2" --output json)
id_a=$(echo "$deliberate_a" | grep -o '"InstanceId": "[^"]*"' | head -1 | cut -d'"' -f4)
id_b=$(echo "$deliberate_b" | grep -o '"InstanceId": "[^"]*"' | head -1 | cut -d'"' -f4)
placed_a=$(aws ec2 describe-instances --instance-ids "$id_a" \
--query 'Reservations[0].Instances[0].Placement.AvailabilityZone' --output text)
placed_b=$(aws ec2 describe-instances --instance-ids "$id_b" \
--query 'Reservations[0].Instances[0].Placement.AvailabilityZone' --output text)
echo "instance A confirmed in: $placed_a"
echo "instance B confirmed in: $placed_b"
echo
echo "if $placed_a's data centre lost power right now, $placed_b is a physically"
echo "separate facility, on separate power -- unaffected by definition, not by luck."
check "the first instance landed exactly where it was told to" "$placed_a" "$zone1"
check "the second instance landed in a genuinely different zone" "$placed_b" "$zone2"
check "the two zones really are different from each other" "$([ "$zone1" != "$zone2" ] && echo yes)" "yes"
What it printed, when the build ran it
deliberately placing one instance in us-east-1a and another in us-east-1b:
instance A confirmed in: us-east-1a
instance B confirmed in: us-east-1b
if us-east-1a's data centre lost power right now, us-east-1b is a physically
separate facility, on separate power -- unaffected by definition, not by luck.
ok the first instance landed exactly where it was told to
ok the second instance landed in a genuinely different zone
ok the two zones really are different from each other
A region is not automatically a blast-radius boundary either. Some
AWS services (IAM, Route 53, S3's control plane) are global or region-spanning by design;
others are strictly regional. Multi-AZ protects against one data centre failing.
Multi-region protects against an entire region having a bad day -- a much rarer, much
more expensive thing to defend against, and rarely worth it for anything but the most
critical systems.
17 The Shared Responsibility Model
AWS is responsible for the security of the cloud: the
physical data centres, the hypervisor, the network fabric between them. You are
responsible for security in the cloud: how you configure what AWS gives you. The
line moves depending on the service (less is yours for a managed database than for a raw
EC2 instance), but for the services this course covers, the split below is where it
actually falls -- checked against a real, running setting, not just stated.
A bucket that defaults to no encryption -- because that default is your call
AWS did not decide your data needs encryption at rest; it gave you the switch and
waits. Before that switch is touched, asking for the bucket's encryption setting fails --
not with "off," but with "not configured at all."
Encryption at rest: not the default, and not automatic
ran at build time
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20aws s3api create-bucket --bucket encryption-test > /dev/null
echo "asking for this brand-new bucket's encryption setting, before touching anything:"
before=$(aws s3api get-bucket-encryption --bucket encryption-test 2>&1)
before_exit=$?
echo "$before"
echo "(exit status: $before_exit -- a real error, not a quiet 'disabled')"
echo
echo "turning it on -- this half of the model is entirely the customer's responsibility:"
aws s3api put-bucket-encryption --bucket encryption-test \
--server-side-encryption-configuration '{"Rules":[{"ApplyServerSideEncryptionByDefault":{"SSEAlgorithm":"AES256"}}]}'
after=$(aws s3api get-bucket-encryption --bucket encryption-test)
echo "$after"
check "before any configuration, there is no default encryption to find" \
"$([ "$before_exit" -ne 0 ] && echo yes)" "yes"
check "after explicitly configuring it, AES256 encryption is confirmed active" \
"$(echo "$after" | grep -c 'AES256')" "1"
What it printed, when the build ran it
asking for this brand-new bucket's encryption setting, before touching anything:
An error occurred (ServerSideEncryptionConfigurationNotFoundError) when calling the GetBucketEncryption operation: The server side encryption configuration was not found
(exit status: 255 -- a real error, not a quiet 'disabled')
turning it on -- this half of the model is entirely the customer's responsibility:
{
"ServerSideEncryptionConfiguration": {
"Rules": [
{
"ApplyServerSideEncryptionByDefault": {
"SSEAlgorithm": "AES256"
},
"BucketKeyEnabled": false
}
]
}
}
ok before any configuration, there is no default encryption to find
ok after explicitly configuring it, AES256 encryption is confirmed active
What AWS actually guarantees here, on its side of the line. The
physical drives S3 stores your object on, the durability across multiple facilities, and
the infrastructure that would encrypt it correctly once told to -- all AWS's job, done
whether or not you ever look at it. Whether that switch gets flipped at all is
completely outside AWS's side of the line.
Public access: blocked by a setting, not by a wall
The single most common real-world cloud data breach is not a sophisticated attack -- it
is a bucket left reachable from the public internet because nobody explicitly blocked it.
AWS's answer is a setting with four parts, all of which have to be turned on, by the
customer, to matter.
Public access blocking: four settings, all the customer's to set
ran at build time
1
2
3
4
5
6
7
8
9
10
11
12
13aws s3api create-bucket --bucket public-block-test > /dev/null
echo "turning on every part of S3's public access block, explicitly:"
aws s3api put-public-access-block --bucket public-block-test \
--public-access-block-configuration BlockPublicAcls=true,IgnorePublicAcls=true,BlockPublicPolicy=true,RestrictPublicBuckets=true
echo
echo "confirming all four are really on, not assumed:"
block_config=$(aws s3api get-public-access-block --bucket public-block-test)
echo "$block_config"
check "all four public-access-blocking settings are confirmed on" \
"$(echo "$block_config" | grep -c 'true')" "4"
What it printed, when the build ran it
turning on every part of S3's public access block, explicitly:
confirming all four are really on, not assumed:
{
"PublicAccessBlockConfiguration": {
"BlockPublicAcls": true,
"IgnorePublicAcls": true,
"BlockPublicPolicy": true,
"RestrictPublicBuckets": true
}
}
ok all four public-access-blocking settings are confirmed on
This is not a hypothetical risk. Search "S3 bucket exposed" and the
result is years of real incidents at real companies -- not a failure of AWS's
infrastructure, but of a setting exactly like the one above never being turned on. The
Shared Responsibility Model is not a legal disclaimer; it is a precise description of
which failures are yours to prevent.
Where the line moves, by service
The split is not identical for every service -- it shifts with how much AWS manages,
which is the same line Part 5's first lesson (service models) already drew.
- EC2 (IaaS): AWS secures the hypervisor and physical hardware. You
patch the OS, configure the security group, and manage everything running on it.
- S3 (managed storage): AWS secures the storage infrastructure and
durability. You configure encryption, public access, and bucket policies -- exactly the
two settings just demonstrated.
- RDS (managed database): AWS patches the database engine itself and
manages the underlying host. You manage access control, network placement, and your own
schema-level permissions.
- Lambda (FaaS): AWS manages everything except your function's own
code and the permissions you grant it -- the least "yours" of any service in this list.
The single question that locates the line for any service: "what did
I have to explicitly configure, versus what came already correct." Everything in the
second category is AWS's responsibility. Everything in the first is yours -- and Part 13
(Security) returns to this exact idea with real IAM policy evaluation.