Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 17 additions & 4 deletions scripts/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,13 @@ default tag on the resources it creates:
| [`hackforla/incubator`](https://github.com/hackforla/incubator) | `managed-by = terraform-incubator` |
| [`hackforla/devops-security`](https://github.com/hackforla/devops-security) | `managed-by = terraform-devops-security` |

So the absence of that tag is the signal that nothing manages a resource. This
script sweeps the account, reads the tag, and buckets everything three ways.
A third value, `managed-by = exempt`, marks a resource that is deliberately
outside Terraform. Unlike the two above it is applied by hand rather than by a
provider, because by definition no Terraform run will ever touch the resource.

So the absence of any of those values is the signal that nothing manages a
resource. This script sweeps the account, reads the tag, and buckets everything
four ways.

This is a **tag sweep, not a Terraform state diff**. Read
[Blind spots](#blind-spots) before treating the output as an inventory.
Expand Down Expand Up @@ -58,9 +63,17 @@ under-reports.
positives. Currently: IAM groups (AWS exposes no group tagging API at all),
AWS-managed KMS keys, AWS service-linked IAM roles, and the AWS-owned
`FARGATE` / `FARGATE_SPOT` ECS capacity providers.
- **`exempt`** — carrying `managed-by = exempt`, and likewise excluded from the
ratio. These are resources Terraform deliberately does not manage, so counting
them as unmanaged would make them permanent false positives in the same way
untaggable ones would. The clearest case is `hackforla/devops-security`'s own
CI identity and state backend: Terraform managing the credentials and the
bucket it unlocks is a lockout risk. Note the difference from `untaggable` —
that bucket is a fact about AWS, this one is an assertion someone made by
hand, and nothing here checks it.
- **Tagged with an unrecognised `managed-by` value** — appears only when
something stamped a provenance tag that is neither repo's. Worth investigating
when it shows up.
something stamped a provenance tag that is neither repo's and is not `exempt`.
Worth investigating when it shows up.

### Why it does not just use the Resource Groups Tagging API

Expand Down
23 changes: 20 additions & 3 deletions scripts/aws-terraform-coverage.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,9 @@
collectors missed.

Resource types that can never carry a tag are reported as their own category
so they do not read as unmanaged forever.
so they do not read as unmanaged forever. Resources deliberately kept out of
Terraform carry `managed-by = exempt`, applied by hand rather than by any
provider, and are excluded from the ratio for the same reason.

Read the "Blind spots" section of README.md before treating the output as a
complete inventory.
Expand Down Expand Up @@ -71,6 +73,7 @@ $ErrorActionPreference = 'Stop'
$script:TagKey = 'managed-by'
$script:IncubatorValue = 'terraform-incubator'
$script:DevOpsSecurityValue = 'terraform-devops-security'
$script:ExemptValue = 'exempt'
$script:ReadOnlyVerbPattern = '^(describe|list|get)-'

# ---------------------------------------------------------------------------
Expand Down Expand Up @@ -215,6 +218,7 @@ function Get-CoverageBucket {

if ($ManagedBy -eq $script:IncubatorValue) { return $script:IncubatorValue }
if ($ManagedBy -eq $script:DevOpsSecurityValue) { return $script:DevOpsSecurityValue }
if ($ManagedBy -eq $script:ExemptValue) { return $script:ExemptValue }
return 'unmanaged'
}

Expand Down Expand Up @@ -854,8 +858,12 @@ function Write-Section {

function Write-CoverageReport {
$all = @($script:Resources)
$taggable = @($all | Where-Object { $_.Bucket -ne 'untaggable' })
$untaggable = @($all | Where-Object { $_.Bucket -eq 'untaggable' })
$exempt = @($all | Where-Object { $_.Bucket -eq $script:ExemptValue })
# Exempt resources are deliberately outside Terraform, so counting them as
# unmanaged would make them permanent false positives - the same argument that
# keeps untaggable out of the ratio. Both are excluded from it here.
$taggable = @($all | Where-Object { $_.Bucket -ne 'untaggable' -and $_.Bucket -ne $script:ExemptValue })
$incubator = @($taggable | Where-Object { $_.Bucket -eq $script:IncubatorValue })
$security = @($taggable | Where-Object { $_.Bucket -eq $script:DevOpsSecurityValue })
$unmanaged = @($taggable | Where-Object { $_.Bucket -eq 'unmanaged' })
Expand All @@ -870,10 +878,12 @@ function Write-CoverageReport {
[pscustomobject]@{ Bucket = $script:IncubatorValue; Resources = $incubator.Count }
[pscustomobject]@{ Bucket = $script:DevOpsSecurityValue; Resources = $security.Count }
[pscustomobject]@{ Bucket = 'unmanaged'; Resources = $unmanaged.Count }
[pscustomobject]@{ Bucket = $script:ExemptValue; Resources = $exempt.Count }
) | Format-Table -AutoSize | Out-String | Write-Host

Write-Host (" {0} of {1} taggable resources carry a managed-by tag ({2}%)." -f $managed, $total, $percent)
Write-Host (" {0} of {1} in-scope resources carry a managed-by tag ({2}%)." -f $managed, $total, $percent)
Write-Host (" {0} further resources cannot be tagged at all and are excluded from that ratio." -f $untaggable.Count)
Write-Host (" {0} are tagged managed-by=exempt and are excluded from it as well." -f $exempt.Count)

# A managed-by value that is neither repo's means something stamped a
# provenance tag we do not recognise, which is worth surfacing on its own.
Expand All @@ -893,6 +903,10 @@ function Write-CoverageReport {
Format-Table -AutoSize | Out-String | Write-Host
}

Write-Section 'Exempt (deliberately outside Terraform, not counted as unmanaged)'
if ($exempt.Count -eq 0) { Write-Host ' none' }
else { $exempt | Sort-Object Service, Type, Arn | ForEach-Object { Write-Host " $($_.Arn)" } }

Write-Section 'Untaggable (reported separately, not counted as unmanaged)'
if ($untaggable.Count -eq 0) { Write-Host ' none' }
else {
Expand Down Expand Up @@ -923,6 +937,9 @@ function Write-CoverageReport {
'still read as unmanaged until some later apply touches it.'),
@('This says nothing about the reverse direction: a resource in Terraform',
'state that no longer exists in AWS.'),
@('managed-by=exempt is applied by hand, so it records an intention rather',
'than a fact. Nothing here verifies that an exempt resource is genuinely',
'one Terraform should not manage.'),
@('ECS task definitions are reported as the current revision per family,',
'not as every historical revision.')
)
Expand Down