Skip to content

Commit e1d0565

Browse files
authored
[CX-2682, CX-2683, CX-2684] - Move all configuration/secrets to AWS Secret Manager (#2)
* [CX-2682, CX-2684] - Move all configuration/secrets to AWS Secret Manager * CX-2682: Addressed code review changes. * CX-2682: Removed unwanted files. * CX-2683: Fix the code vulnerabilities/snyk reported issues * [CX-2682] Redis TTL & Ping endpoint. * CX-2682: Addressed code review changes.
1 parent e5de1c1 commit e1d0565

File tree

9 files changed

+281
-169
lines changed

9 files changed

+281
-169
lines changed

Dockerfile

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# Build the application from source
2+
FROM golang:1.21.5 AS build-stage
3+
4+
WORKDIR /app
5+
6+
COPY go.mod go.sum ./
7+
RUN go mod download
8+
9+
COPY . .
10+
11+
RUN CGO_ENABLED=0 GOOS=linux go build -o /server main.go
12+
13+
# Deploy the application binary into a lean image
14+
FROM alpine:3.21.3 AS build-release-stage
15+
16+
RUN apk update \
17+
&& apk --no-cache add ca-certificates \
18+
&& apk --no-cache add -U tzdata \
19+
&& rm -rf /var/cache/apk/*
20+
21+
WORKDIR /usr/app/
22+
23+
COPY --from=build-stage server .
24+
25+
EXPOSE 8080
26+
ENTRYPOINT ["./server"]

config/app.json

Lines changed: 0 additions & 3 deletions
This file was deleted.

config/app.prod.json

Lines changed: 0 additions & 44 deletions
This file was deleted.

config/config.go

Lines changed: 187 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -2,61 +2,25 @@ package config
22

33
import (
44
"encoding/json"
5+
"fmt"
56
"os"
6-
"os/exec"
7-
"path/filepath"
7+
"strconv"
88
"strings"
9-
)
10-
11-
var configFile *appConfig
12-
13-
func getExcPath() string {
14-
file, _ := exec.LookPath(os.Args[0])
15-
// 获取包含可执行文件名称的路径
16-
path, _ := filepath.Abs(file)
17-
// 获取可执行文件所在目录
18-
index := strings.LastIndex(path, string(os.PathSeparator))
19-
ret := path[:index]
20-
return strings.Replace(ret, "\\", "/", -1)
21-
}
22-
23-
func GetConfig() appConfig {
24-
if configFile != nil {
25-
return *configFile
26-
}
27-
path := getExcPath()
28-
var mode modeConfig = readJson[modeConfig](path + "/config/app.json")
29-
30-
appConfig := readJson[appConfig](path + "/config/app." + mode.Mode + ".json")
31-
configFile = &appConfig
32-
return *configFile
33-
}
34-
35-
func readJson[T any](path string) T {
36-
file, err := os.Open(path)
37-
if err != nil {
38-
panic(path + " config not found")
39-
}
40-
defer file.Close()
41-
decoder := json.NewDecoder(file)
9+
"sync"
4210

43-
var jsonF T
44-
decoder.Decode(&jsonF)
45-
return jsonF
46-
}
47-
48-
type modeConfig struct {
49-
Mode string
50-
}
11+
"github.com/go-playground/validator/v10"
12+
)
5113

5214
type appConfig struct {
5315
DBUser dbConfig
5416
Redis redisConfig
5517
CodePush codePush
5618
UrlPrefix string
5719
Port string
58-
ResourceUrl string
20+
ResourceUrl string `json:"resource_url" validate:"required"`
5921
TokenExpireTime int64
22+
Environment string `json:"environment" validate:"required"`
23+
TenantName string `json:"tenant_name" validate:"required"`
6024
}
6125
type dbConfig struct {
6226
Write dbConfigObj
@@ -65,38 +29,196 @@ type dbConfig struct {
6529
ConnMaxLifetime uint
6630
}
6731
type dbConfigObj struct {
68-
UserName string
69-
Password string
70-
Host string
71-
Port uint
72-
DBname string
32+
UserName string `json:"db_username" validate:"required"`
33+
Password string `json:"db_password" validate:"required"`
34+
Host string `json:"db_host" validate:"required"`
35+
Port uint `json:"db_port" validate:"required"`
36+
DBname string `json:"db_name" validate:"required"`
7337
}
7438
type redisConfig struct {
75-
Host string
76-
Port uint
77-
DBIndex uint
78-
UserName string
79-
Password string
39+
Host string `json:"redis_host" validate:"required"`
40+
Port uint `json:"redis_port" validate:"required"`
41+
DBIndex uint `json:"redis_db_index"`
42+
UserName string `json:"redis_username"`
43+
Password string `json:"redis_password"`
8044
}
8145
type codePush struct {
82-
FileLocal string
46+
FileLocal string `json:"build_save_location" validate:"required"`
8347
Local localConfig
8448
Aws awsConfig
8549
Ftp ftpConfig
8650
}
8751
type awsConfig struct {
88-
Endpoint string
89-
Region string
90-
S3ForcePathStyle bool
91-
KeyId string
92-
Secret string
93-
Bucket string
52+
Endpoint string `json:"aws_s3_endpoint" validate:"required"`
53+
Region string `json:"aws_region" validate:"required"`
54+
S3ForcePathStyle bool `json:"aws_s3_force_path_style" validate:"required"`
55+
KeyId string `json:"aws_access_key_id" validate:"required"`
56+
Secret string `json:"aws_secret_access_key" validate:"required"`
57+
Bucket string `json:"aws_s3_bucket_name" validate:"required"`
9458
}
9559
type ftpConfig struct {
96-
ServerUrl string
97-
UserName string
98-
Password string
60+
ServerUrl string `json:"ftp_server_url"`
61+
UserName string `json:"ftp_username"`
62+
Password string `ftp_password`
9963
}
10064
type localConfig struct {
101-
SavePath string
65+
SavePath string `json:"local_build_save_path"`
66+
}
67+
68+
var config *appConfig
69+
var once sync.Once
70+
71+
func GetConfig() *appConfig {
72+
once.Do(func() {
73+
config = LoadConfig()
74+
})
75+
return config
76+
}
77+
78+
func LoadConfig() *appConfig {
79+
fmt.Println("Fetching config from AWS secret manager...")
80+
keys := []string{
81+
"global", // Global secrets
82+
"tenant", // Tendancy punchh-server secrets
83+
"service", // Email template secrets
84+
"db", // DB secrets
85+
}
86+
87+
var config appConfig
88+
89+
var dbObj dbConfigObj
90+
var redis redisConfig
91+
var buildSaveLocation codePush
92+
var aws awsConfig
93+
var ftp ftpConfig
94+
95+
// default values
96+
config.DBUser.MaxIdleConns = 5
97+
config.DBUser.MaxOpenConns = 20
98+
config.DBUser.ConnMaxLifetime = 300
99+
100+
config.Port = ":8080"
101+
config.UrlPrefix = "/"
102+
config.ResourceUrl = ""
103+
config.TokenExpireTime = 1 //in days
104+
105+
for _, key := range keys {
106+
key = key + "_secrets"
107+
108+
data, ok := os.LookupEnv(key)
109+
if !ok {
110+
fmt.Println("config: no secrets found for - ", key)
111+
continue
112+
}
113+
114+
secrets := make(map[string]interface{})
115+
if err := json.Unmarshal([]byte(data), &secrets); err != nil {
116+
fmt.Println("config: error unmarshalling secrets for - ", key)
117+
panic(err)
118+
}
119+
120+
for k, v := range secrets {
121+
k = strings.ToLower(k)
122+
fmt.Println(k)
123+
// DB
124+
if k == "db_username" {
125+
dbObj.UserName = v.(string)
126+
}
127+
if k == "db_password" {
128+
dbObj.Password = v.(string)
129+
}
130+
if k == "db_host" {
131+
dbObj.Host = v.(string)
132+
}
133+
if k == "db_port" {
134+
u64, _ := strconv.ParseUint(v.(string), 10, 32)
135+
dbObj.Port = uint(u64)
136+
}
137+
if k == "db_name" {
138+
dbObj.DBname = v.(string)
139+
}
140+
141+
// Redis
142+
if k == "redis_host" {
143+
redis.Host = v.(string)
144+
}
145+
if k == "redis_port" {
146+
u64, _ := strconv.ParseUint(v.(string), 10, 32)
147+
redis.Port = uint(u64)
148+
}
149+
if k == "redis_db_index" {
150+
u64, _ := strconv.ParseUint(v.(string), 10, 32)
151+
redis.DBIndex = uint(u64)
152+
}
153+
if k == "redis_username" {
154+
redis.UserName = v.(string)
155+
}
156+
if k == "redis_password" {
157+
redis.Password = v.(string)
158+
}
159+
160+
// local bundle save location
161+
if k == "build_save_location" {
162+
buildSaveLocation.FileLocal = v.(string)
163+
}
164+
165+
// AWS
166+
if k == "aws_s3_endpoint" {
167+
aws.Endpoint = v.(string)
168+
}
169+
if k == "aws_region" {
170+
aws.Region = v.(string)
171+
}
172+
if k == "aws_s3_force_path_style" {
173+
aws.S3ForcePathStyle = true
174+
}
175+
if k == "aws_access_key_id" {
176+
aws.KeyId = v.(string)
177+
}
178+
if k == "aws_secret_access_key" {
179+
aws.Secret = v.(string)
180+
}
181+
if k == "aws_s3_bucket_name" {
182+
aws.Bucket = v.(string)
183+
}
184+
185+
// ftp
186+
if k == "ftp_server_url" {
187+
ftp.ServerUrl = v.(string)
188+
}
189+
if k == "ftp_username" {
190+
ftp.UserName = v.(string)
191+
}
192+
if k == "ftp_password" {
193+
ftp.Password = v.(string)
194+
}
195+
// common
196+
197+
// if build_save_location is set to `local` then resource URL should the self server URL
198+
// if build_save_location is set to `aws` then resource URL should the AWS S3 bucket URL
199+
if k == "resource_url" {
200+
config.ResourceUrl = v.(string)
201+
}
202+
if k == "tenant_name" {
203+
config.TenantName = v.(string)
204+
}
205+
206+
if k == "environment" {
207+
config.Environment = v.(string)
208+
}
209+
}
210+
}
211+
config.DBUser.Write = dbObj
212+
config.Redis = redis
213+
config.CodePush = buildSaveLocation
214+
config.CodePush.Aws = aws
215+
config.CodePush.Ftp = ftp
216+
217+
// validate the config
218+
validate := validator.New()
219+
if err := validate.Struct(config); err != nil {
220+
fmt.Println("config: invalid/missing configuration", err)
221+
panic(err)
222+
}
223+
return &config
102224
}

0 commit comments

Comments
 (0)