Skip to content
academia.sh

Lesson 01 / 12

Cloud Service Models and Responsibility

Translating the shared-responsibility boundary into an audit list: 21 items that can be misconfigured are classified across three service models, the items that can be automatically audited drop from 15 to 12 and 7 while the items left outside the audit list rise from 6 to 9 and 14, the share of seed weight goes from 35% to 51% and 66%, unowned items rise from 0 to 2 and 4, and the 28-unit blind spot that no list can read stays fixed across all three models.

Published Updated

In this lesson

  • Separates configuration items that can be misconfigured into four classes: audited, known by declaration, blind spot, and unowned
  • Counts how the items and seed weight covered by the audit list narrow as the service model goes deeper
  • Shows separately the weight that taking ownership of an unowned item closes and the blind spot it cannot close
Contents

The previous course built the evidence chain all the way through, and at every step it carried the same silent assumption: the machine under examination is reachable. In rented infrastructure that assumption falls away. The hardware belongs to someone else, the host operating system is invisible, and the physical machine the instance runs on cannot even be named. This pushes the evidence question to later and brings forward a question that comes earlier: where the misconfiguration can be, and whose list that misconfiguration is on.

This course uses a single measure: blast radius — how many items are reached from a single misconfigured item. Measuring the radius first requires a list of the items where a misconfiguration can sit. Shared responsibility splits that list in two; this lesson turns the split into an audit list and counts what falls outside it. The responsibility matrix itself was measured in the Cloud Fundamentals course of the Cloud Computing curriculum and is not re-derived here — it is taken as input.

  • CM1. Everything below belongs to a fictional regional measurement network: meter collection, verification, invoice generation, and the subscriber portal all run on rented infrastructure. No real provider, service, region, or organization name appears; what is measured is a model written with node.
  • CM2. A misconfigurable item is a configuration item that opens access when its value is set incorrectly. Twenty-one items are counted; the list is illustrative, not exhaustive.
  • CM3. In each of the three service models, every item is set either by the customer, by the provider, or by no one at all. The third case does not come from the contract; it comes from each side assuming the other one handles it.
  • CM4. Readability is a separate property: an item’s effective value is either readable from the management plane or not readable at all. An item the provider sets is known to the customer only by declaration.
  • CM5. Seed weight is the number of items directly opened up if an item is misconfigured. It is a fictional number, used in this lesson only to weight the items; the walk itself is run in the next lesson.
  • CM6. A row in the audit list can only run automatically if the item is both owned and readable. In every other case, the cost of the row changes.

Items That Can Be Misconfigured

The model writes items with three columns — who sets it, per service model — and carries two more properties: readability and seed weight. Four classes are derived from these three.

// cloud/item.mjs — the MODEL of items that can be misconfigured in rented infrastructure.
// Fictional regional measurement network; no real provider, service, region, or contract name.

export const MODEL = ['infrastructure', 'platform', 'function'];
// Columns: who sets the item (C customer, P provider, N nobody) x three service models.
// read: how the item's effective value is read by the customer.
//   interface = read from the management plane, none = read from neither an interface nor a document.
// touch: number of items directly opened if the item is misconfigured (seed weight, fictional).
export const ITEM = `
  physical-access               P P P  interface    6
  hypervisor-patch               P P P  interface   14
  co-tenancy                     P P P  interface   11
  host-kernel-patch              C P P  interface    9
  runtime-version                C C P  interface    5
  image-source                   C C P  interface    7
  instance-metadata-version      C N P  interface    8
  management-endpoint-exposure   C N N  interface   10
  network-access-rule            C C N  interface    6
  private-endpoint-mapping       C C N  interface    4
  log-stream-destination         C C N  interface    3
  role-trust-list                 C C C  interface   12
  identity-role-definition        C C C  interface    9
  storage-permission-set          C C C  interface    7
  storage-public-flag             C C C  interface    5
  key-ownership                   C C C  interface    8
  secret-store-access             C C C  interface   13
  audit-log-enabled               C C C  interface    2
  template-default                C C C  none         9
  dependency-version              C C C  none         4
  in-workload-secret              C C C  none        15`
  .trim().split('\n').map((s) => {
    const [name, ...k] = s.trim().split(/\s+/);
    return { name, read: k[3], touch: Number(k[4]),
      side: Object.fromEntries(MODEL.map((m, i) => [m, k[i]])) };
  });

// Audit-list class: who sees this if the item is misconfigured, and with what.
export const classOf = (k, m) => k.side[m] === 'N' ? 'unowned'
  : k.side[m] === 'P' ? 'declared'
    : k.read === 'interface' ? 'audited' : 'blind';
export const CLASS = ['audited', 'declared', 'blind', 'unowned'];
// Cost of the audit row: rule that runs automatically, periodic question round, extra mechanism, owner assignment.
export const COST = { audited: 'rule', declared: 'question round', blind: 'extra mechanism',
  unowned: 'owner first' };
export const group = (m, c) => ITEM.filter((k) => classOf(k, m) === c);
export const weight = (l) => l.reduce((a, k) => a + k.touch, 0);
export const TOTAL = weight(ITEM);
// cloud/run1.mjs — how many items are on the customer, how many are declared, how many are unowned; how many are outside the audit list
import { ITEM, MODEL, CLASS, TOTAL, group, weight, classOf } from './item.mjs';

const print = (g, ...s) => console.log(s.map((v, i) =>
  g[i] < 0 ? String(v).padEnd(-g[i]) : String(v).padStart(g[i])).join(''));
const A = [-30, 16, 16, 16];
const changed = ITEM.filter((k) => new Set(MODEL.map((m) => classOf(k, m))).size > 1);
console.log(`${ITEM.length} items that can be misconfigured, total seed weight ${TOTAL}; ` +
  `${changed.length} items whose class changes across the three models:\n`);
print(A, 'item', ...MODEL);
for (const k of changed) print(A, k.name, ...MODEL.map((m) => classOf(k, m)));

console.log('');
print(A, 'class (21-item breakdown)', ...MODEL);
for (const c of CLASS) print(A, c, ...MODEL.map((m) => group(m, c).length));
print(A, 'outside the audit list', ...MODEL.map((m) =>
  CLASS.slice(1).reduce((a, c) => a + group(m, c).length, 0)));
print(A, '  seed weight', ...MODEL.map((m) =>
  CLASS.slice(1).reduce((a, c) => a + weight(group(m, c)), 0)));
print(A, '  weight percentage', ...MODEL.map((m) =>
  Math.round(CLASS.slice(1).reduce((a, c) => a + weight(group(m, c)), 0) / TOTAL * 100)));
21 items that can be misconfigured, total seed weight 167; 8 items whose class changes across the three models:

item                            infrastructure        platform        function
host-kernel-patch                      audited        declared        declared
runtime-version                        audited         audited        declared
image-source                           audited         audited        declared
instance-metadata-version              audited         unowned        declared
management-endpoint-exposure           audited         unowned         unowned
network-access-rule                    audited         audited         unowned
private-endpoint-mapping               audited         audited         unowned
log-stream-destination                 audited         audited         unowned

class (21-item breakdown)       infrastructure        platform        function
audited                                     15              12               7
declared                                     3               4               7
blind                                        3               3               3
unowned                                      0               2               4
outside the audit list                       6               9              14
  seed weight                               59              86             111
  weight percentage                         35              51              66

The top table shows only the eight items whose class changes; the remaining thirteen items stay in the same class across all three models. The bottom table gives the actual counts: the items the customer can read from the management plane and audit automatically drop from fifteen to twelve, then to seven. In the same direction, the items left outside the audit list rise from six to nine, then to fourteen.

The seed-weight row shows why this shift is not a flat trade. The share of the total weight of 167 units that the audit list cannot see goes from 35% to 51%, then to 66%. The item count grows by a little more than double, while the weight share nearly triples — because the items that drop off the list are the heavy ones. hypervisor-patch carries fourteen, in-workload-secret fifteen, secret-store-access thirteen units.

The List Narrows as the Boundary Shifts

The top table separates four groups of items. host-kernel-patch, runtime-version, and image-source move to the provider explicitly: the customer does not set them, the provider takes them over, and the audit turns into a declaration. This is not a loss but a trade — the item can still be misconfigured, but the party that can fix the misconfiguration is the same party that made it.

network-access-rule, private-endpoint-mapping, and log-stream-destination take a different path. The customer sets them in the infrastructure and platform models; in the function model, the execution environment abstracts these items away and the provider does not take them over under contract either. The result is unownedness: the item can still be misconfigured, but because no one sets it, no one audits it.

management-endpoint-exposure stays unowned in two models at once, and at ten units of weight it is the heaviest unowned item on the list. instance-metadata-version follows an interesting path: the customer sets it in infrastructure, no one sets it in platform, and the provider takes it over in function. As the boundary shifts deeper, an item does not always cross in a straight line — it can fall into a gap in one model along the way.

The Cost of the Audit List

Each of the four classes enters the audit list at a different cost. For an owned, readable item, a rule is written and it runs continuously. For an item known by declaration, a periodic question is put to the provider; the accuracy of the answer cannot be tested, only recorded. A blind spot needs an extra mechanism to pull its value out of the running system. An unowned item fits none of these: before a row can be written, the item’s owner must first be assigned.

// cloud/run2.mjs — audit list: how many rows run automatically, how many need a question round
import { MODEL, CLASS, COST, TOTAL, group, weight } from './item.mjs';

const print = (g, ...s) => console.log(s.map((v, i) =>
  g[i] < 0 ? String(v).padEnd(-g[i]) : String(v).padStart(g[i])).join(''));
const B = [-13, -18, 16, 16, 16];
print(B, 'class', 'row cost', ...MODEL);
for (const c of CLASS)
  print(B, c, COST[c], ...MODEL.map((m) => `${group(m, c).length} / ${weight(group(m, c))}`));
console.log('  (cell: item count / seed weight)\n');

const C = [-16, 9, 10, 9, 14, 12];
print(C, 'model', 'audit', 'covered', 'question', 'no owner', 'blind');
print(C, '', 'rows', 'weight', 'round', 'item/weight', 'weight');
for (const m of MODEL)
  print(C, m, group(m, 'audited').length,
    `${Math.round(weight(group(m, 'audited')) / TOTAL * 100)}%`,
    group(m, 'declared').length,
    `${group(m, 'unowned').length} / ${weight(group(m, 'unowned'))}`,
    weight(group(m, 'blind')));
class        row cost            infrastructure        platform        function
audited      rule                      15 / 108         12 / 81          7 / 56
declared     question round              3 / 31          4 / 40          7 / 60
blind        extra mechanism             3 / 28          3 / 28          3 / 28
unowned      owner first                  0 / 0          2 / 18          4 / 23
  (cell: item count / seed weight)

model               audit   covered question      no owner       blind
                     rows    weight    round   item/weight      weight
infrastructure         15       65%        3         0 / 0          28
platform               12       49%        4        2 / 18          28
function                7       34%        7        4 / 23          28

The first table breaks the cost down class by class. In the infrastructure model, fifteen rows run automatically and cover a hundred and eight units of weight; in the function model, only seven rows remain and the covered weight drops to fifty-six. The question round rises from three to seven: each round is an item that is asked of the provider, whose answer is awaited, and that cannot be tested.

The second table reads the same three models in a single row. The automatically covered weight drops from 65% to 34%. Unowned items rise from zero to two and four, and their weight from zero to eighteen and twenty-three. For these items the customer has one option — take on ownership — and when it is taken on, eighteen and twenty-three units return to the list. The cost is that work not in the contract gets written onto the customer’s own team.

How Many Days Later Is the Misconfiguration Seen

Row count gives the width of the list, not its delay. A rule that runs automatically sees the misconfiguration on the day it is set; a periodic question round sees it only on the day the round comes around; if an extra mechanism collects weekly, it sees it within the week. An unowned item is never asked at all.

// cloud/run3.mjs — how many days later a misconfigured item is noticed; which weight is never noticed
import { MODEL, CLASS, TOTAL, group, weight } from './item.mjs';

// Detection delay (days): a rule runs continuously, a question round is periodic,
// an extra mechanism collects weekly once installed, an unowned item is never asked.
const DELAY = { audited: 0, declared: 90, blind: 7, unowned: null };
const print = (g, ...s) => console.log(s.map((v, i) =>
  g[i] < 0 ? String(v).padEnd(-g[i]) : String(v).padStart(g[i])).join(''));
const D = [-16, 9, 15, 16, 17];
print(D, 'model', 'observed', 'weighted', 'never observed', 'blind mechanism');
print(D, '', 'weight', 'delay (days)', 'weight', 'if absent');
for (const m of MODEL) {
  const g = CLASS.filter((c) => DELAY[c] !== null);
  const seen = g.reduce((a, c) => a + weight(group(m, c)), 0);
  const sum = g.reduce((a, c) => a + weight(group(m, c)) * DELAY[c], 0);
  print(D, m, seen, (sum / seen).toFixed(1), TOTAL - seen,
    TOTAL - seen + weight(group(m, 'blind')));
}
console.log('\ncontribution to delay from weight falling under question round instead of rule:');
for (const m of MODEL)
  console.log(`  ${m.padEnd(15)}declared weight ${String(weight(group(m, 'declared'))).padStart(3)}` +
    `, ${Math.round(weight(group(m, 'declared')) * 90 /
      (weight(group(m, 'declared')) * 90 + weight(group(m, 'blind')) * 7) * 100)}% of the delay comes from here`);
model            observed       weighted  never observed  blind mechanism
                   weight   delay (days)          weight        if absent
infrastructure        167           17.9               0               28
platform              149           25.5              18               46
function              144           38.9              23               51

contribution to delay from weight falling under question round instead of rule:
  infrastructure declared weight  31, 93% of the delay comes from here
  platform       declared weight  40, 95% of the delay comes from here
  function       declared weight  60, 96% of the delay comes from here

The weighted delay goes from seventeen point nine days to twenty-five point five, then to thirty-eight point nine. In other words, the same misconfigured item sits in place, on average, more than twice as long in the function model. The bottom block says where the delay comes from: across all three models, the share running from 93% to 96% comes from the declared class. The blind spot’s weekly mechanism contributes almost nothing to the delay, because seven days is small next to ninety.

The last column carries a warning. The never-observed weight is zero, eighteen, and twenty-three — but that number assumes an extra mechanism has been installed for the blind spot. If the mechanism is not installed, the never-observed weight rises to twenty-eight, forty-six, and fifty-one; in the function model, roughly a third of the total weight never lands on any list. This is not a gap in the audit list’s width: the list can be written as twenty-one rows and some of those rows will still never read a value.

The Blind Spot Does Not Change With the Boundary

The last column carries this lesson’s decisive number: the weight no list can read is twenty-eight units in all three models. Three items — template default, dependency version, and the in-workload secret — belong to the customer in all three models, can be misconfigured in all three, and cannot be read from the management plane in any of the three.

This means deepening the service model does not shrink the blind spot. The boundary moves items between customer and provider; it does not move readability. Taking on an unowned item does not close the blind spot either — even after the platform model’s two unowned items are taken on, twenty-eight units remain in place, because ownership was already with the customer; what was missing was visibility.

The audit list must therefore do three separate jobs at once: continuously test an owned, visible item with a rule, record the provider’s item through a question round, and pull the invisible item out of the running system. The list at the end of this lesson has twenty-one rows, and in the function model only seven of those rows run on their own.

Summary

  • The 21 items that can be misconfigured split into four classes: audited, known by declaration, blind spot, unowned. Total seed weight is 167 units.
  • Automatically audited items go 15 → 12 → 7; items left outside the audit list go 6 → 9 → 14. Covered weight goes 65% → 49% → 34%.
  • The weight share drops faster than the item count, because the items that drop off the list are the heavy ones: hypervisor-patch carries 14, in-workload-secret 15, secret-store-access 13 units.
  • Unowned items go 0 → 2 → 4 and their weight 0 → 18 → 23. During the shift, an item can fall into a gap in one model instead of crossing over; instance-metadata-version is an example of this.
  • Weighted detection delay goes 17.9 → 25.5 → 38.9 days. 93% to 96% of the delay comes from the declared class; the blind spot’s weekly mechanism contributes almost nothing to the delay.
  • The weight no list can read is 28 units in all three models. The boundary moves items, not readability; taking on an unowned item does not lower these 28 units either.

Next Step

The list is now written: twenty-one items, four classes, and a seed weight for each item. But seed weight was given in this lesson as a number, not computed. secret-store-access was said to carry thirteen, but where the thirteen comes from, and how many of those thirteen items are reached directly and how many through another identity, was never asked. The next lesson builds this course’s unit of measure: identities and items are written as an access graph, the walk from a single leaked identity is actually run, and the radius becomes a number.

To keep your progress and take notes, Log in

My notes

Log in to take notes.

Start typing to search.

↑↓ ↵ Esc navigate · open · close