|
| 1 | +# AzureServiceBus Destination configuration |
| 2 | + |
| 3 | +Here's a rough document explaining how AzureServiceBus works and how the destination is implemented with Outpost. |
| 4 | + |
| 5 | +# PubSub vs Queue |
| 6 | + |
| 7 | +Azure ServiceBus supports both PubSub (Topic & Subscription) and Queue. From the Publisher (Azure's term is Sender) perspective, it doesn't really care whether it's publishing to a Topic or to a Queue. So, from the destination config, all we need is a single "name" field. |
| 8 | + |
| 9 | +## Message |
| 10 | + |
| 11 | +Whether it's publishing to Topic or Queue, the Publisher needs to send an Azure's Message. Here's the full Golang SDK Message struct: |
| 12 | + |
| 13 | +```golang |
| 14 | +// Message is a message with a body and commonly used properties. |
| 15 | +// Properties that are pointers are optional. |
| 16 | +type Message struct { |
| 17 | + // ApplicationProperties can be used to store custom metadata for a message. |
| 18 | + ApplicationProperties map[string]any |
| 19 | + |
| 20 | + // Body corresponds to the first []byte array in the Data section of an AMQP message. |
| 21 | + Body []byte |
| 22 | + |
| 23 | + // ContentType describes the payload of the message, with a descriptor following |
| 24 | + // the format of Content-Type, specified by RFC2045 (ex: "application/json"). |
| 25 | + ContentType *string |
| 26 | + |
| 27 | + // CorrelationID allows an application to specify a context for the message for the purposes of |
| 28 | + // correlation, for example reflecting the MessageID of a message that is being |
| 29 | + // replied to. |
| 30 | + CorrelationID *string |
| 31 | + |
| 32 | + // MessageID is an application-defined value that uniquely identifies |
| 33 | + // the message and its payload. The identifier is a free-form string. |
| 34 | + // |
| 35 | + // If enabled, the duplicate detection feature identifies and removes further submissions |
| 36 | + // of messages with the same MessageId. |
| 37 | + MessageID *string |
| 38 | + |
| 39 | + // PartitionKey is used with a partitioned entity and enables assigning related messages |
| 40 | + // to the same internal partition. This ensures that the submission sequence order is correctly |
| 41 | + // recorded. The partition is chosen by a hash function in Service Bus and cannot be chosen |
| 42 | + // directly. |
| 43 | + // |
| 44 | + // For session-aware entities, the ReceivedMessage.SessionID overrides this value. |
| 45 | + PartitionKey *string |
| 46 | + |
| 47 | + // ReplyTo is an application-defined value specify a reply path to the receiver of the message. When |
| 48 | + // a sender expects a reply, it sets the value to the absolute or relative path of the queue or topic |
| 49 | + // it expects the reply to be sent to. |
| 50 | + ReplyTo *string |
| 51 | + |
| 52 | + // ReplyToSessionID augments the ReplyTo information and specifies which SessionId should |
| 53 | + // be set for the reply when sent to the reply entity. |
| 54 | + ReplyToSessionID *string |
| 55 | + |
| 56 | + // ScheduledEnqueueTime specifies a time when a message will be enqueued. The message is transferred |
| 57 | + // to the broker but will not available until the scheduled time. |
| 58 | + ScheduledEnqueueTime *time.Time |
| 59 | + |
| 60 | + // SessionID is used with session-aware entities and associates a message with an application-defined |
| 61 | + // session ID. Note that an empty string is a valid session identifier. |
| 62 | + // Messages with the same session identifier are subject to summary locking and enable |
| 63 | + // exact in-order processing and demultiplexing. For session-unaware entities, this value is ignored. |
| 64 | + SessionID *string |
| 65 | + |
| 66 | + // Subject enables an application to indicate the purpose of the message, similar to an email subject line. |
| 67 | + Subject *string |
| 68 | + |
| 69 | + // TimeToLive is the duration after which the message expires, starting from the instant the |
| 70 | + // message has been accepted and stored by the broker, found in the ReceivedMessage.EnqueuedTime |
| 71 | + // property. |
| 72 | + // |
| 73 | + // When not set explicitly, the assumed value is the DefaultTimeToLive for the queue or topic. |
| 74 | + // A message's TimeToLive cannot be longer than the entity's DefaultTimeToLive is silently |
| 75 | + // adjusted if it does. |
| 76 | + TimeToLive *time.Duration |
| 77 | + |
| 78 | + // To is reserved for future use in routing scenarios but is not currently used by Service Bus. |
| 79 | + // Applications can use this value to indicate the logical destination of the message. |
| 80 | + To *string |
| 81 | +} |
| 82 | +``` |
| 83 | + |
| 84 | +Here are a few notable configuration, especially on the destination level that we may want to support: |
| 85 | + |
| 86 | +- MessageID --> MessageIDTemplate, similar to AWS Kinesis Parition Key approach |
| 87 | +- CorrelationID --> CorrelationIDTemplate, similar to AWS Kinesis Parition Key approach |
| 88 | +- PartitionKey --> PartitionKeyTemplate, similar to AWS Kinesis Parition Key approach |
| 89 | + |
| 90 | +- ScheduledEnqueueTime |
| 91 | +- TimeToLive |
| 92 | + |
| 93 | +The current implementation doesn't support any of these. So when create destination, it's super straightforward: |
| 94 | + |
| 95 | +```golang |
| 96 | +type Config struct { |
| 97 | + Name string |
| 98 | +} |
| 99 | +``` |
| 100 | + |
| 101 | +If we want to support these, we can either add them to Config, such as `Config.TTL`, or we can also add a suffix like `Config.MessageTTL` to specify that these config would apply to the Message. |
| 102 | + |
| 103 | +## Authentication |
| 104 | + |
| 105 | +For authentication, we currently support "connection_string" which by default have access to the full Namespace. |
| 106 | + |
| 107 | +## Creating Topic/Queue-Specific Access Policy |
| 108 | + |
| 109 | +### For a Topic (Send-only access): |
| 110 | + |
| 111 | +Create a Send-only policy for a specific topic |
| 112 | + |
| 113 | +az servicebus topic authorization-rule create \ |
| 114 | + --resource-group outpost-demo-rg \ |
| 115 | + --namespace-name outpost-demo-sb-${RANDOM_SUFFIX} \ |
| 116 | + --topic-name events \ |
| 117 | + --name SendOnlyPolicy \ |
| 118 | + --rights Send |
| 119 | + |
| 120 | +Get the Topic-Specific Connection String: |
| 121 | + |
| 122 | +az servicebus topic authorization-rule keys list \ |
| 123 | + --resource-group outpost-demo-rg \ |
| 124 | + --namespace-name outpost-demo-sb-${RANDOM_SUFFIX} \ |
| 125 | + --topic-name events \ |
| 126 | + --name SendOnlyPolicy \ |
| 127 | + --query primaryConnectionString \ |
| 128 | + --output tsv |
| 129 | + |
| 130 | +This returns a connection string that can only send to the events topic: |
| 131 | +Endpoint=sb://outpost-demo-sb-a3f2b1.servicebus.windows.net/;SharedAccessKeyName=Send |
| 132 | +OnlyPolicy;SharedAccessKey=xyz789...;EntityPath=events |
| 133 | + |
| 134 | +### For Queues (similar approach): |
| 135 | + |
| 136 | +Create a Send-only policy for a specific queue |
| 137 | +az servicebus queue authorization-rule create \ |
| 138 | + --resource-group outpost-demo-rg \ |
| 139 | + --namespace-name outpost-demo-sb-${RANDOM_SUFFIX} \ |
| 140 | + --queue-name myqueue \ |
| 141 | + --name SendOnlyPolicy \ |
| 142 | + --rights Send |
| 143 | + |
| 144 | +Available Permission Rights: |
| 145 | + |
| 146 | +- Send - Can only send messages |
| 147 | +- Listen - Can only receive messages |
| 148 | +- Manage - Full control (send, receive, manage) |
| 149 | + |
| 150 | +You can combine multiple rights: |
| 151 | +--rights Send Listen # Can both send and receive |
| 152 | + |
| 153 | +Benefits of Entity-Level Access: |
| 154 | + |
| 155 | +1. Security: Limits blast radius if credentials are compromised |
| 156 | +2. Principle of Least Privilege: Outpost only needs Send permission |
| 157 | +3. Audit Trail: Can track which policy is being used |
| 158 | +4. Rotation: Can rotate entity-specific keys without affecting other services |
| 159 | + |
| 160 | +Important Notes: |
| 161 | + |
| 162 | +- Entity-level connection strings include EntityPath parameter |
| 163 | +- These policies are scoped to a single topic/queue |
| 164 | +- Perfect for production where you want to limit Outpost to only sending to specific |
| 165 | +topics |
| 166 | +- The connection string format is the same, just with limited scope |
| 167 | + |
| 168 | +This is the recommended approach for production use - give Outpost only the minimum |
| 169 | +permissions it needs (Send) and only to the specific topic/queue it should access. |
0 commit comments