Documentation
¶
Overview ¶
Package sql implements the azure.sql source plugin: it enumerates Azure's three managed relational-database services in a subscription and emits one cross-vendor managed_database_instance record per database/server, so encryption-at-rest, public-access, backup, SSL, and multi-AZ policies evaluate against Azure exactly as they do against AWS RDS and GCP Cloud SQL — zero policy changes (Invariant #4, substitutability).
Three families, one plugin (mirrors aws.rds covering every engine):
- Azure SQL (armsql): one record per database, excluding the `master` system database. Transparent Data Encryption (TDE) is per-database, so this family is an N+1+1 walk — list servers, list databases per server, GET TDE state per database.
- PostgreSQL Flexible Server (armpostgresqlflexibleservers): one record per server.
- MySQL Flexible Server (armmysqlflexibleservers): one record per server.
Honest mappings (the plugin owns 100% of the vendor→canonical translation):
- storage_encrypted: a REAL toggle for Azure SQL (TDE can be disabled per database), but a platform CONSTANT true for the flexible servers (their at-rest encryption is always-on and cannot be disabled — Microsoft- managed by default, optionally CMEK; the cmek_enabled extra carries that distinction).
- backup_enabled: true for all three — Azure SQL Database always retains automated point-in-time backups (cannot be disabled), and the flexible servers always run automated backups (BackupRetentionDays has a 7-day floor). The backup_retention_days extra makes that auditable.
- publicly_accessible: from the SERVER-level public-network-access flag (it gates every database on an Azure SQL logical server). A flag ARM does not report reads as accessible, never as private.
- ssl_required: emitted as true ONLY for Azure SQL, which enforces encrypted connections unconditionally. For the flexible servers SSL enforcement is a server PARAMETER (require_secure_transport / ssl), not a ServerProperties field; rather than fabricate a value the field is OMITTED, so the is_set-guarded SSL policy skips those records instead of false-failing them.
- deletion_protection: false for every Azure managed database — none expose a deletion-protection property. The Azure mechanism is an ARM resource lock (CanNotDelete), which is not a database property and is not read here; customers cover that control via a resource lock + an exception or manual evidence.
A list/GET failure (e.g. a missing-permission 403) is surfaced as an error rather than silently reporting an insecure default, which would be misleading false-fail evidence; the error tags only the azure.sql-bound policies `error`, not a run crash.
Test injection: the API interface is the single seam and returns raw SDK types so 100% of the vendor→canonical mapping stays in Collect under fakeAPI unit tests; the real adapter (realSQL) wraps the armsql / armpostgresql / armmysql SDK clients. Real-adapter HTTP behavior is covered with httptest; deeper integration coverage is deferred to the testing strategy revamp.
Index ¶
Constants ¶
const EvidenceTypeID = "managed_database_instance"
EvidenceTypeID is the cross-vendor managed_database_instance shape. Azure's managed databases are substitutable sources alongside AWS RDS and GCP Cloud SQL.
const SourceID = "azure.sql"
SourceID is the registered ID for the azure.sql plugin instance.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type API ¶
type API interface {
// ListSQLServers returns every Azure SQL logical server in the subscription.
ListSQLServers(ctx context.Context) ([]*armsql.Server, error)
// ListSQLDatabases returns the databases on one Azure SQL server (includes
// the `master` system database; the caller filters it out).
ListSQLDatabases(ctx context.Context, resourceGroup, server string) ([]*armsql.Database, error)
// GetSQLDatabaseTDEState returns the current Transparent Data Encryption
// state for one database, nil when unavailable.
GetSQLDatabaseTDEState(ctx context.Context, resourceGroup, server, database string) (*armsql.TransparentDataEncryptionState, error)
// ListPostgresServers returns every PostgreSQL Flexible Server in the subscription.
ListPostgresServers(ctx context.Context) ([]*armpg.Server, error)
// ListMySQLServers returns every MySQL Flexible Server in the subscription.
ListMySQLServers(ctx context.Context) ([]*armmysql.Server, error)
}
API is the subset of the Azure management plane this plugin uses across the three managed-database services. It returns raw SDK types so the vendor→canonical mapping is exercised by fakeAPI unit tests; the real adapter (realSQL) wraps the armsql / armpostgresql / armmysql clients.
type Options ¶
type Options struct {
API API
SubscriptionID string
// Now is injected so tests can produce deterministic CollectedAt values.
// Production callers leave it nil → time.Now().UTC().
Now func() time.Time
}
Options is the constructor input.
type Plugin ¶
type Plugin struct {
// contains filtered or unexported fields
}
Plugin is the in-process azure.sql source.
func New ¶
New constructs a Plugin around an explicit API implementation. Callers using the real Azure SDK should use NewFromAzure.
func NewFromAzure ¶
NewFromAzure constructs a Plugin backed by the real Azure SDK clients using the given credential (a DefaultAzureCredential) scoped to cfg.SubscriptionID.
func (*Plugin) Caveats ¶ added in v0.85.0
func (*Plugin) Caveats() []core.SourceCaveat
Caveats declares the one field this plugin emits without observing it. See the package doc: none of the three managed-database families — Azure SQL, PostgreSQL flexible server, MySQL flexible server — exposes a deletion-protection property, so deletion_protection is emitted as a constant false at all three emit sites. The Azure mechanism is an ARM resource lock (CanNotDelete), which is not a database property and is not read here, so a customer whose databases ARE lock-protected still fails the policy. The planner turns this into a warning when a deletion-protection policy binds this source.
One caveat, not three: a caveat is keyed by evidence type and field, and all three families emit the same managed_database_instance type. Per-emit-site caveats would repeat one warning three times and imply a per-family distinction that does not exist.
Unconditional: no credential and no permission makes this readable from the database resource — the property does not exist on any of the three.
func (*Plugin) Collect ¶
func (p *Plugin) Collect(ctx context.Context, req core.SlotRequest) ([]core.EvidenceRecord, error)
Collect enumerates Azure SQL databases plus PostgreSQL/MySQL flexible servers in the configured subscription and emits one managed_database_instance record each, sorted by ID (ARM resource id) so envelope bytes are stable across runs against stable state.