Created
September 15, 2025 04:36
-
-
Save sireza/854cc3e90d974ba0010b651a5d3caad7 to your computer and use it in GitHub Desktop.
Cassandra Managed Instance - Bicep Module
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@description('Name of the Cassandra managed instance') | |
param cassandraClusterName string | |
@description('Location for all resources') | |
param location string = resourceGroup().location | |
@description('Resource ID of the existing virtual network') | |
param vnetId string | |
@description('Name of the subnet for Cassandra deployment') | |
param subnetName string | |
@description('Administrator password for the Cassandra cluster') | |
@secure() | |
param adminPassword string | |
@description('Number of Cassandra nodes in the cluster') | |
@minValue(3) | |
@maxValue(12) | |
param nodeCount int = 3 | |
@description('Tags to apply to all resources') | |
param tags object = {} | |
@description('Cassandra version') | |
@allowed([ | |
'3.11' | |
'4.0' | |
]) | |
param cassandraVersion string = '4.0' | |
@description('Number of disks per node') | |
@minValue(1) | |
@maxValue(10) | |
param diskCount int = 4 | |
@description('SKU for the Cassandra cluster') | |
@allowed([ | |
'Standard_D8s_v4' | |
'Standard_D16s_v4' | |
'Standard_D32s_v4' | |
'Standard_E8s_v4' | |
'Standard_E16s_v4' | |
'Standard_E32s_v4' | |
]) | |
param sku string = 'Standard_D8s_v4' | |
@description('Enable encryption in transit (required for ISM compliance)') | |
param enableEncryptionInTransit bool = true | |
@description('Resource ID of Log Analytics workspace for audit logging (required for ISM compliance)') | |
param logAnalyticsWorkspaceId string | |
@description('Enable comprehensive audit logging (required for ISM compliance)') | |
param enableAuditLogging bool = true | |
@description('Data retention period in days for audit logs (minimum 7 years for ISM compliance)') | |
@minValue(2555) // 7 years | |
@maxValue(2555) | |
param auditLogRetentionDays int = 2555 | |
@description('ISM classification level') | |
@allowed([ | |
'OFFICIAL' | |
'OFFICIAL:Sensitive' | |
'PROTECTED' | |
'SECRET' | |
]) | |
param ismClassification string = 'OFFICIAL' | |
// Get reference to the existing subnet | |
resource subnet 'Microsoft.Network/virtualNetworks/subnets@2023-05-01' existing = { | |
name: '${last(split(vnetId, '/'))}/${subnetName}' | |
scope: resourceGroup(split(vnetId, '/')[2], split(vnetId, '/')[4]) | |
} | |
// Create the Cassandra managed instance cluster | |
resource cassandraCluster 'Microsoft.DocumentDB/cassandraClusters@2023-04-15' = { | |
name: cassandraClusterName | |
location: location | |
tags: union(tags, { | |
'ISM-Classification': ismClassification | |
'Data-Encryption-Transit': enableEncryptionInTransit ? 'Enabled' : 'Disabled' | |
'Data-Encryption-Rest': 'Azure-Managed' | |
'Audit-Logging': enableAuditLogging ? 'Enabled' : 'Disabled' | |
'ISM-Compliant': enableEncryptionInTransit && enableAuditLogging ? 'Yes' : 'No' | |
}) | |
properties: { | |
delegatedManagementSubnetId: subnet.id | |
cassandraVersion: cassandraVersion | |
clientCertificates: [] | |
externalGossipCertificates: [] | |
externalSeedNodes: [] | |
hoursBetweenBackups: 24 | |
authenticationMethod: 'Cassandra' | |
initialCassandraAdminPassword: adminPassword | |
prometheusEndpoint: { | |
ipAddress: '10.0.0.1' | |
} | |
repairEnabled: true | |
restoreFromBackupId: null | |
} | |
} | |
// Create data center for the Cassandra cluster | |
resource cassandraDataCenter 'Microsoft.DocumentDB/cassandraClusters/dataCenters@2023-04-15' = { | |
parent: cassandraCluster | |
name: '${cassandraClusterName}-dc1' | |
properties: { | |
dataCenterLocation: location | |
delegatedSubnetId: subnet.id | |
nodeCount: nodeCount | |
sku: sku | |
diskSku: 'P30' | |
diskCapacity: diskCount | |
base64EncodedCassandraYamlFragment: base64(''' | |
# Cassandra configuration fragment | |
num_tokens: 256 | |
hinted_handoff_enabled: true | |
max_hint_window_in_ms: 10800000 | |
hinted_handoff_throttle_in_kb: 1024 | |
max_hints_delivery_threads: 2 | |
hints_directory: /var/lib/cassandra/hints | |
hints_flush_period_in_ms: 10000 | |
max_hints_file_size_in_mb: 128 | |
batchlog_replay_throttle_in_kb: 1024 | |
authenticator: PasswordAuthenticator | |
authorizer: CassandraAuthorizer | |
role_manager: CassandraRoleManager | |
roles_validity_in_ms: 2000 | |
permissions_validity_in_ms: 2000 | |
credentials_validity_in_ms: 2000 | |
partitioner: org.apache.cassandra.dht.Murmur3Partitioner | |
data_file_directories: | |
- /var/lib/cassandra/data | |
commitlog_directory: /var/lib/cassandra/commitlog | |
disk_failure_policy: stop | |
commit_failure_policy: stop | |
key_cache_size_in_mb: | |
key_cache_save_period: 14400 | |
row_cache_size_in_mb: 0 | |
row_cache_save_period: 0 | |
counter_cache_size_in_mb: | |
counter_cache_save_period: 7200 | |
saved_caches_directory: /var/lib/cassandra/saved_caches | |
commitlog_sync: periodic | |
commitlog_sync_period_in_ms: 10000 | |
commitlog_segment_size_in_mb: 32 | |
concurrent_reads: 32 | |
concurrent_writes: 32 | |
concurrent_counter_writes: 32 | |
concurrent_materialized_view_writes: 32 | |
memtable_allocation_type: heap_buffers | |
index_summary_capacity_in_mb: | |
index_summary_resize_interval_in_minutes: 60 | |
trickle_fsync: false | |
trickle_fsync_interval_in_kb: 10240 | |
storage_port: 7000 | |
ssl_storage_port: 7001 | |
listen_address: localhost | |
start_native_transport: true | |
native_transport_port: 9042 | |
start_rpc: false | |
rpc_address: localhost | |
rpc_port: 9160 | |
rpc_keepalive: true | |
rpc_server_type: sync | |
thrift_framed_transport_size_in_mb: 15 | |
incremental_backups: false | |
snapshot_before_compaction: false | |
auto_snapshot: true | |
tombstone_warn_threshold: 1000 | |
tombstone_failure_threshold: 100000 | |
column_index_size_in_kb: 64 | |
batch_size_warn_threshold_in_kb: 5 | |
batch_size_fail_threshold_in_kb: 50 | |
compaction_throughput_mb_per_sec: 16 | |
compaction_large_partition_warning_threshold_mb: 100 | |
sstable_preemptive_open_interval_mb: 50 | |
read_request_timeout_in_ms: 5000 | |
range_request_timeout_in_ms: 10000 | |
write_request_timeout_in_ms: 2000 | |
counter_write_request_timeout_in_ms: 5000 | |
cas_contention_timeout_in_ms: 1000 | |
truncate_request_timeout_in_ms: 60000 | |
request_timeout_in_ms: 10000 | |
slow_query_log_timeout_in_ms: 500 | |
cross_node_timeout: false | |
endpoint_snitch: SimpleSnitch | |
dynamic_snitch_update_interval_in_ms: 100 | |
dynamic_snitch_reset_interval_in_ms: 600000 | |
dynamic_snitch_badness_threshold: 0.1 | |
request_scheduler: org.apache.cassandra.scheduler.NoScheduler | |
server_encryption_options: | |
internode_encryption: ${enableEncryptionInTransit ? 'all' : 'none'} | |
keystore: conf/.keystore | |
keystore_password: cassandra | |
truststore: conf/.truststore | |
truststore_password: cassandra | |
protocol: TLS | |
algorithm: SunX509 | |
store_type: JKS | |
cipher_suites: [TLS_RSA_WITH_AES_128_CBC_SHA,TLS_RSA_WITH_AES_256_CBC_SHA,TLS_DHE_RSA_WITH_AES_128_CBC_SHA,TLS_DHE_RSA_WITH_AES_256_CBC_SHA,TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA] | |
require_client_auth: true | |
client_encryption_options: | |
enabled: ${enableEncryptionInTransit} | |
optional: false | |
keystore: conf/.keystore | |
keystore_password: cassandra | |
require_client_auth: true | |
protocol: TLS | |
algorithm: SunX509 | |
store_type: JKS | |
cipher_suites: [TLS_RSA_WITH_AES_128_CBC_SHA,TLS_RSA_WITH_AES_256_CBC_SHA,TLS_DHE_RSA_WITH_AES_128_CBC_SHA,TLS_DHE_RSA_WITH_AES_256_CBC_SHA,TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA] | |
internode_compression: dc | |
inter_dc_tcp_nodelay: false | |
tracetype_query_ttl: 86400 | |
tracetype_repair_ttl: 604800 | |
gc_warn_threshold_in_ms: 1000 | |
enable_user_defined_functions: false | |
enable_scripted_user_defined_functions: false | |
windows_timer_interval: 1 | |
transparent_data_encryption_options: | |
enabled: true | |
chunk_length_kb: 64 | |
cipher: AES/CBC/PKCS5Padding | |
key_alias: testing:1 | |
key_provider: | |
- class_name: org.apache.cassandra.security.JKSKeyProvider | |
parameters: | |
- keystore: conf/.keystore | |
keystore_password: cassandra | |
store_type: JCEKS | |
key_password: cassandra | |
''') | |
} | |
} | |
// Configure diagnostic settings for ISM compliance audit logging | |
resource cassandraAuditLogs 'Microsoft.Insights/diagnosticSettings@2021-05-01-preview' = if (enableAuditLogging) { | |
name: '${cassandraClusterName}-audit-logs' | |
scope: cassandraCluster | |
properties: { | |
workspaceId: logAnalyticsWorkspaceId | |
logs: [ | |
{ | |
category: 'DataPlaneRequests' | |
enabled: true | |
retentionPolicy: { | |
enabled: true | |
days: auditLogRetentionDays | |
} | |
} | |
{ | |
category: 'QueryRuntimeStatistics' | |
enabled: true | |
retentionPolicy: { | |
enabled: true | |
days: auditLogRetentionDays | |
} | |
} | |
{ | |
category: 'PartitionKeyStatistics' | |
enabled: true | |
retentionPolicy: { | |
enabled: true | |
days: auditLogRetentionDays | |
} | |
} | |
{ | |
category: 'PartitionKeyRUConsumption' | |
enabled: true | |
retentionPolicy: { | |
enabled: true | |
days: auditLogRetentionDays | |
} | |
} | |
] | |
metrics: [ | |
{ | |
category: 'Requests' | |
enabled: true | |
retentionPolicy: { | |
enabled: true | |
days: auditLogRetentionDays | |
} | |
} | |
] | |
} | |
} | |
// Output values | |
@description('Cassandra cluster name') | |
output cassandraClusterName string = cassandraCluster.name | |
@description('Cassandra cluster resource ID') | |
output cassandraClusterId string = cassandraCluster.id | |
@description('Cassandra cluster seed nodes') | |
output seedNodes array = cassandraCluster.properties.seedNodes | |
@description('Cassandra cluster gossip port') | |
output gossipPort int = 7000 | |
@description('Cassandra cluster CQL port') | |
output cqlPort int = 9042 | |
@description('Data center name') | |
output dataCenterName string = cassandraDataCenter.name | |
@description('Data center resource ID') | |
output dataCenterId string = cassandraDataCenter.id | |
@description('ISM compliance status') | |
output ismCompliant bool = enableEncryptionInTransit && enableAuditLogging | |
@description('Encryption in transit status') | |
output encryptionInTransitEnabled bool = enableEncryptionInTransit | |
@description('Audit logging status') | |
output auditLoggingEnabled bool = enableAuditLogging | |
@description('ISM classification level') | |
output classification string = ismClassification |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment