Skip to content

Commit 586152b

Browse files
committed
Add basic auth to backup endpoint.
1 parent c746f03 commit 586152b

File tree

7 files changed

+108
-7
lines changed

7 files changed

+108
-7
lines changed

cmd/mysql-helper/appclone/appclone.go

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ package appclone
1818

1919
import (
2020
"fmt"
21-
"net/http"
2221
"os"
2322
"os/exec"
2423
"strings"
@@ -151,7 +150,7 @@ func cloneFromBucket(initBucket string) error {
151150
func cloneFromSource(host string) error {
152151
glog.Infof("Cloning from node: %s", host)
153152

154-
resp, err := http.Get(fmt.Sprintf("http://%s:%d%s", host, tb.ServerPort, tb.ServerBackupPath))
153+
backupBody, err := tb.RequestABackup(host, tb.ServerBackupPath)
155154
if err != nil {
156155
return fmt.Errorf("fail to get backup: %s", err)
157156
}
@@ -161,7 +160,7 @@ func cloneFromSource(host string) error {
161160
// data target dir
162161
xbstream := exec.Command("xbstream", "-x", "-C", tb.DataDir)
163162

164-
xbstream.Stdin = resp.Body
163+
xbstream.Stdin = backupBody
165164
xbstream.Stderr = os.Stderr
166165

167166
if err := xbstream.Start(); err != nil {

cmd/mysql-helper/apphelper/server.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,11 @@ func (s *server) healthHandle(w http.ResponseWriter, r *http.Request) {
6363

6464
func (s *server) serveBackupHandle(w http.ResponseWriter, r *http.Request) {
6565

66+
if !s.isAuthenticated(r) {
67+
http.Error(w, "Not authenticated!", http.StatusForbidden)
68+
return
69+
}
70+
6671
flusher, ok := w.(http.Flusher)
6772
if !ok {
6873
http.Error(w, "Streamming unsupported!", http.StatusInternalServerError)
@@ -107,3 +112,8 @@ func (s *server) serveBackupHandle(w http.ResponseWriter, r *http.Request) {
107112
return
108113
}
109114
}
115+
116+
func (s *server) isAuthenticated(r *http.Request) bool {
117+
user, pass, ok := r.BasicAuth()
118+
return ok && user == tb.GetBackupUser() && pass == tb.GetBackupPass()
119+
}

cmd/mysql-helper/apptakebackup/apptakebackup.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ package apptakebackup
1818

1919
import (
2020
"fmt"
21-
"net/http"
2221
"os"
2322
"os/exec"
2423
"strings"
@@ -39,17 +38,18 @@ func RunTakeBackupCommand(stopCh <-chan struct{}, srcHost, destBucket string) er
3938
}
4039

4140
func pushBackupFromTo(srcHost, destBucket string) error {
42-
resp, err := http.Get(fmt.Sprintf("http://%s:%d%s", srcHost, tb.ServerPort, tb.ServerBackupPath))
41+
42+
backupBody, err := tb.RequestABackup(srcHost, tb.ServerBackupPath)
4343
if err != nil {
44-
return fmt.Errorf("fail to get backup: %s", err)
44+
return fmt.Errorf("getting backup: %s", err)
4545
}
4646

4747
gzip := exec.Command("gzip", "-c")
4848

4949
rclone := exec.Command("rclone",
5050
fmt.Sprintf("--config=%s", tb.RcloneConfigFile), "rcat", destBucket)
5151

52-
gzip.Stdin = resp.Body
52+
gzip.Stdin = backupBody
5353
gzip.Stderr = os.Stderr
5454
rclone.Stderr = os.Stderr
5555

cmd/mysql-helper/util/util.go

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,16 @@ func GetInitBucket() string {
171171
return getEnvValue("INIT_BUCKET_URI")
172172
}
173173

174+
// GetBackupAccessUser returns the basic auth credentials to access backup
175+
func GetBackupUser() string {
176+
return getEnvValue("MYSQL_BACKUP_USER")
177+
}
178+
179+
// GetBackupAccessUser returns the basic auth credentials to access backup
180+
func GetBackupPass() string {
181+
return getEnvValue("MYSQL_BACKUP_PASSWORD")
182+
}
183+
174184
// GetMasterHost returns the master host
175185
func GetMasterHost() string {
176186
orcUri := getOrcUri()
@@ -298,3 +308,24 @@ func MaxClients(h http.Handler, n int) http.Handler {
298308
h.ServeHTTP(w, r)
299309
})
300310
}
311+
312+
func RequestABackup(host, path string) (io.Reader, error) {
313+
glog.Infof("Initiate a backup from: %s path: %s", host, path)
314+
315+
req, err := http.NewRequest("GET", fmt.Sprintf("http://%s:%d%s", host, ServerPort, path), nil)
316+
if err != nil {
317+
return nil, fmt.Errorf("fail to create request: %s", err)
318+
}
319+
320+
// set authentification user and password
321+
req.SetBasicAuth(GetBackupUser(), GetBackupPass())
322+
323+
client := &http.Client{}
324+
325+
resp, err := client.Do(req)
326+
if err != nil || resp.StatusCode != 200 {
327+
return nil, fmt.Errorf("fail to get backup: %s, code: %s", err, resp.Status)
328+
}
329+
330+
return resp.Body, nil
331+
}

pkg/backupfactory/backupfactory.go

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,34 @@ func (f *bFactory) ensurePodSpec(in core.PodSpec) core.PodSpec {
107107
f.GetBackupUri(),
108108
}
109109

110+
boolTrue := true
111+
in.Containers[0].Env = []core.EnvVar{
112+
core.EnvVar{
113+
Name: "MYSQL_BACKUP_USER",
114+
ValueFrom: &core.EnvVarSource{
115+
SecretKeyRef: &core.SecretKeySelector{
116+
LocalObjectReference: core.LocalObjectReference{
117+
Name: f.cluster.Spec.SecretName,
118+
},
119+
Key: "BACKUP_USER",
120+
Optional: &boolTrue,
121+
},
122+
},
123+
},
124+
core.EnvVar{
125+
Name: "MYSQL_BACKUP_PASSWORD",
126+
ValueFrom: &core.EnvVarSource{
127+
SecretKeyRef: &core.SecretKeySelector{
128+
LocalObjectReference: core.LocalObjectReference{
129+
Name: f.cluster.Spec.SecretName,
130+
},
131+
Key: "BACKUP_PASSWORD",
132+
Optional: &boolTrue,
133+
},
134+
},
135+
},
136+
}
137+
110138
if len(f.GetBackupSecretName()) != 0 {
111139
in.Containers[0].EnvFrom = []core.EnvFromSource{
112140
core.EnvFromSource{

pkg/mysqlcluster/secret.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,14 @@ func (f *cFactory) syncClusterSecret() (state string, err error) {
6969
in.Data["ORC_TOPOLOGY_USER"] = []byte(f.opt.OrchestratorTopologyUser)
7070
in.Data["ORC_TOPOLOGY_PASSWORD"] = []byte(f.opt.OrchestratorTopologyPassword)
7171

72+
if len(in.Data["BACKUP_USER"]) == 0 {
73+
in.Data["BACKUP_USER"] = []byte(util.RandomString(rStrLen))
74+
}
75+
76+
if len(in.Data["BACKUP_PASSWORD"]) == 0 {
77+
in.Data["BACKUP_PASSWORD"] = []byte(util.RandomString(rStrLen))
78+
}
79+
7280
hash, err := hashstructure.Hash(in.Data, nil)
7381
if err != nil {
7482
glog.Errorf("Can't compute the hash for db secret: %s", err)

pkg/mysqlcluster/statefullset.go

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,31 @@ func (f *cFactory) getEnvFor(name string) (env []core.EnvVar) {
261261
},
262262
},
263263
})
264+
case containerCloneName:
265+
env = append(env, core.EnvVar{
266+
Name: "MYSQL_BACKUP_USER",
267+
ValueFrom: &core.EnvVarSource{
268+
SecretKeyRef: &core.SecretKeySelector{
269+
LocalObjectReference: core.LocalObjectReference{
270+
Name: f.cluster.Spec.SecretName,
271+
},
272+
Key: "BACKUP_USER",
273+
Optional: &boolTrue,
274+
},
275+
},
276+
})
277+
env = append(env, core.EnvVar{
278+
Name: "MYSQL_BACKUP_PASSWORD",
279+
ValueFrom: &core.EnvVarSource{
280+
SecretKeyRef: &core.SecretKeySelector{
281+
LocalObjectReference: core.LocalObjectReference{
282+
Name: f.cluster.Spec.SecretName,
283+
},
284+
Key: "BACKUP_PASSWORD",
285+
Optional: &boolTrue,
286+
},
287+
},
288+
})
264289
}
265290

266291
return

0 commit comments

Comments
 (0)