Skip to content

Instantly share code, notes, and snippets.

@sireza
Created September 15, 2025 04:36
Show Gist options
  • Save sireza/854cc3e90d974ba0010b651a5d3caad7 to your computer and use it in GitHub Desktop.
Save sireza/854cc3e90d974ba0010b651a5d3caad7 to your computer and use it in GitHub Desktop.
Cassandra Managed Instance - Bicep Module
@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