11package admin
22
33import (
4+ "context"
45 "crypto/tls"
56 "crypto/x509"
67 "encoding/json"
@@ -9,12 +10,17 @@ import (
910 "strings"
1011 "time"
1112
12- "github.com/aws/aws-sdk-go/aws"
13- "github.com/aws/aws-sdk-go/aws/arn"
13+ // "github.com/aws/aws-sdk-go/aws"
14+ // "github.com/aws/aws-sdk-go/aws/arn"
15+ // "github.com/aws/aws-sdk-go/aws/session"
16+ // sigv4 "github.com/aws/aws-sdk-go/aws/signer/v4"
17+ // "github.com/aws/aws-sdk-go/service/secretsmanager"
18+ // "github.com/aws/aws-sdk-go/service/secretsmanager/secretsmanageriface"
19+ "github.com/aws/aws-sdk-go-v2/aws"
20+ sigv4 "github.com/aws/aws-sdk-go-v2/aws/signer/v4"
21+ awsCfg "github.com/aws/aws-sdk-go-v2/config"
22+ "github.com/aws/aws-sdk-go-v2/service/secretsmanager"
1423 "github.com/aws/aws-sdk-go/aws/session"
15- sigv4 "github.com/aws/aws-sdk-go/aws/signer/v4"
16- "github.com/aws/aws-sdk-go/service/secretsmanager"
17- "github.com/aws/aws-sdk-go/service/secretsmanager/secretsmanageriface"
1824 "github.com/segmentio/kafka-go"
1925 "github.com/segmentio/kafka-go/sasl"
2026 "github.com/segmentio/kafka-go/sasl/aws_msk_iam"
@@ -67,6 +73,15 @@ type Connector struct {
6773 KafkaClient * kafka.Client
6874}
6975
76+ // ARN is a parsed Amazon Resource Name.
77+ type ARN struct {
78+ Partition string
79+ Service string
80+ Region string
81+ AccountID string
82+ Resource string
83+ }
84+
7085// NewConnector contructs a new Connector instance given the argument config.
7186func NewConnector (config ConnectorConfig ) (* Connector , error ) {
7287 connector := & Connector {
@@ -80,10 +95,16 @@ func NewConnector(config ConnectorConfig) (*Connector, error) {
8095 if config .SASL .Enabled {
8196 saslUsername := config .SASL .Username
8297 saslPassword := config .SASL .Password
98+ ctx := context .Background ()
8399
84100 if config .SASL .SecretsManagerArn != "" {
85- secretProvider := secretsmanager .New (session .Must (session .NewSession ()))
86- creds , err := GetKafkaCredentials (secretProvider , config .SASL .SecretsManagerArn )
101+ cfg , err := awsCfg .LoadDefaultConfig (ctx )
102+ if err != nil {
103+ return nil , err
104+ }
105+ secretProvider := secretsmanager .NewFromConfig (cfg )
106+
107+ creds , err := GetKafkaCredentials (ctx , secretProvider , config .SASL .SecretsManagerArn )
87108 if err != nil {
88109 return nil , err
89110 }
@@ -220,16 +241,24 @@ type credentials struct {
220241 Password string `json:"password"`
221242}
222243
223- func GetKafkaCredentials (svc secretsmanageriface. SecretsManagerAPI , secretArn string ) (credentials , error ) {
244+ func GetKafkaCredentials (ctx context. Context , svc * secretsmanager. Client , secretArn string ) (credentials , error ) {
224245 log .Debugf ("Fetching credentials from Secrets Manager for secret: %s" , secretArn )
225246 var creds credentials
226247
227- arn , err := arn . Parse (secretArn )
248+ arn , err := ParseARN (secretArn )
228249 if err != nil {
229250 return creds , fmt .Errorf ("Couldn't parse the ARN for secret: %s, error: %v" , secretArn , err )
230251 }
231- // Remove "secret:" from the resource to get the secret name
232- secretName := strings .Split (arn .Resource , ":" )[1 ]
252+
253+ // Adding additional ARN validation as the AWS SDK v2 does not provide this functionality
254+ secretParts := strings .Split (arn .Resource , ":" )
255+ if len (secretParts ) < 2 {
256+ return creds , fmt .Errorf ("invalid resource format in ARN: %s" , secretArn )
257+ }
258+ secretName := secretParts [1 ]
259+ if len (secretName ) < 7 {
260+ return creds , fmt .Errorf ("secret name too short: %s" , secretName )
261+ }
233262 // Strip the six random characters at the end of the arn to get the secret name
234263 // https://docs.aws.amazon.com/secretsmanager/latest/userguide/getting-started.html
235264 secretNameNoSuffix := secretName [:len (secretName )- 7 ]
@@ -240,12 +269,38 @@ func GetKafkaCredentials(svc secretsmanageriface.SecretsManagerAPI, secretArn st
240269 SecretId : aws .String (secretNameNoSuffix ),
241270 }
242271
243- result , err := svc .GetSecretValue (input )
272+ result , err := svc .GetSecretValue (ctx , input )
244273 if err != nil {
245274 return creds , err
246275 }
247276
248- json .Unmarshal ([]byte (* result .SecretString ), & creds )
277+ if result .SecretString == nil {
278+ return creds , fmt .Errorf ("SecretString is nil for secret: %s" , secretNameNoSuffix )
279+ }
280+
281+ if err := json .Unmarshal ([]byte (* result .SecretString ), & creds ); err != nil {
282+ return creds , err
283+ }
249284
250285 return creds , nil
251286}
287+
288+ // ParseARN parses an AWS ARN string into its components.
289+ // Example ARN: arn:aws:secretsmanager:us-west-2:123456789012:secret:mysecret-abc123
290+ func ParseARN (arnStr string ) (ARN , error ) {
291+ const arnPrefix = "arn:"
292+ if ! strings .HasPrefix (arnStr , arnPrefix ) {
293+ return ARN {}, fmt .Errorf ("invalid ARN: %s" , arnStr )
294+ }
295+ parts := strings .SplitN (arnStr , ":" , 6 )
296+ if len (parts ) < 6 {
297+ return ARN {}, fmt .Errorf ("invalid ARN format: %s" , arnStr )
298+ }
299+ return ARN {
300+ Partition : parts [1 ],
301+ Service : parts [2 ],
302+ Region : parts [3 ],
303+ AccountID : parts [4 ],
304+ Resource : parts [5 ],
305+ }, nil
306+ }
0 commit comments