|
1 | 1 | package models
|
2 | 2 |
|
3 | 3 | import (
|
| 4 | + "bytes" |
| 5 | + "context" |
4 | 6 | "fmt"
|
5 | 7 | "net/url"
|
| 8 | + "os" |
| 9 | + "os/exec" |
6 | 10 | "regexp"
|
7 |
| - "strings" |
8 | 11 | "time"
|
9 | 12 |
|
10 | 13 | "github.com/flanksource/duty/types"
|
@@ -153,33 +156,100 @@ func (c Connection) AsGoGetterURL() (string, error) {
|
153 | 156 | }
|
154 | 157 |
|
155 | 158 | // AsEnv generates environment variables and a configuration file content based on the connection type.
|
156 |
| -func (c Connection) AsEnv() ([]string, string) { |
157 |
| - var ( |
158 |
| - envs []string |
159 |
| - file strings.Builder |
160 |
| - ) |
| 159 | +func (c Connection) AsEnv() EnvPrep { |
| 160 | + envPrep := EnvPrep{ |
| 161 | + Conn: c, |
| 162 | + } |
161 | 163 |
|
162 | 164 | switch c.Type {
|
163 | 165 | case ConnectionTypeAWS:
|
164 |
| - envs = append(envs, fmt.Sprintf("AWS_ACCESS_KEY_ID=%s", c.Username)) |
165 |
| - envs = append(envs, fmt.Sprintf("AWS_SECRET_ACCESS_KEY=%s", c.Password)) |
| 166 | + envPrep.Env = append(envPrep.Env, fmt.Sprintf("AWS_ACCESS_KEY_ID=%s", c.Username)) |
| 167 | + envPrep.Env = append(envPrep.Env, fmt.Sprintf("AWS_SECRET_ACCESS_KEY=%s", c.Password)) |
166 | 168 |
|
167 |
| - file.WriteString("[default]\n") |
168 |
| - file.WriteString(fmt.Sprintf("aws_access_key_id = %s\n", c.Username)) |
169 |
| - file.WriteString(fmt.Sprintf("aws_secret_access_key = %s\n", c.Password)) |
| 169 | + envPrep.File.WriteString("[default]\n") |
| 170 | + envPrep.File.WriteString(fmt.Sprintf("aws_access_key_id = %s\n", c.Username)) |
| 171 | + envPrep.File.WriteString(fmt.Sprintf("aws_secret_access_key = %s\n", c.Password)) |
170 | 172 |
|
171 | 173 | if v, ok := c.Properties["profile"]; ok {
|
172 |
| - envs = append(envs, fmt.Sprintf("AWS_DEFAULT_PROFILE=%s", v)) |
| 174 | + envPrep.Env = append(envPrep.Env, fmt.Sprintf("AWS_DEFAULT_PROFILE=%s", v)) |
173 | 175 | }
|
174 | 176 |
|
175 | 177 | if v, ok := c.Properties["region"]; ok {
|
176 |
| - envs = append(envs, fmt.Sprintf("AWS_DEFAULT_REGION=%s", v)) |
177 |
| - file.WriteString(fmt.Sprintf("region = %s\n", v)) |
| 178 | + envPrep.Env = append(envPrep.Env, fmt.Sprintf("AWS_DEFAULT_REGION=%s", v)) |
| 179 | + envPrep.File.WriteString(fmt.Sprintf("region = %s\n", v)) |
178 | 180 | }
|
179 | 181 |
|
| 182 | + case ConnectionTypeAzure: |
| 183 | + // Do nothing |
| 184 | + |
180 | 185 | case ConnectionTypeGCP:
|
181 |
| - file.WriteString(c.Certificate) |
| 186 | + envPrep.File.WriteString(c.Certificate) |
| 187 | + } |
| 188 | + |
| 189 | + return envPrep |
| 190 | +} |
| 191 | + |
| 192 | +type EnvPrep struct { |
| 193 | + Conn Connection |
| 194 | + |
| 195 | + // Env is the connection credentials in environment variables |
| 196 | + Env []string |
| 197 | + |
| 198 | + // File contains the content of the configuration file based on the connection |
| 199 | + File bytes.Buffer |
| 200 | +} |
| 201 | + |
| 202 | +func (c *EnvPrep) Apply(ctx context.Context, cmd *exec.Cmd, configAbsPath string) error { |
| 203 | + switch c.Conn.Type { |
| 204 | + case ConnectionTypeAWS: |
| 205 | + if err := saveConfig(c.File.Bytes(), configAbsPath); err != nil { |
| 206 | + return err |
| 207 | + } |
| 208 | + |
| 209 | + cmd.Env = append(cmd.Env, "AWS_EC2_METADATA_DISABLED=true") // https://github.com/aws/aws-cli/issues/5262#issuecomment-705832151 |
| 210 | + cmd.Env = append(cmd.Env, fmt.Sprintf("AWS_SHARED_CREDENTIALS_FILE=%s", configAbsPath)) |
| 211 | + if v, ok := c.Conn.Properties["region"]; ok { |
| 212 | + cmd.Env = append(cmd.Env, fmt.Sprintf("AWS_DEFAULT_REGION=%s", v)) |
| 213 | + } |
| 214 | + |
| 215 | + case ConnectionTypeGCP: |
| 216 | + if err := saveConfig(c.File.Bytes(), configAbsPath); err != nil { |
| 217 | + return err |
| 218 | + } |
| 219 | + |
| 220 | + // to configure gcloud CLI to use the service account specified in GOOGLE_APPLICATION_CREDENTIALS, |
| 221 | + // we need to explicitly activate it |
| 222 | + runCmd := exec.Command("gcloud", "auth", "activate-service-account", "--key-file", configAbsPath) |
| 223 | + if err := runCmd.Run(); err != nil { |
| 224 | + return fmt.Errorf("failed to activate GCP service account: %w", err) |
| 225 | + } |
| 226 | + |
| 227 | + cmd.Env = append(cmd.Env, fmt.Sprintf("GOOGLE_APPLICATION_CREDENTIALS=%s", configAbsPath)) |
| 228 | + |
| 229 | + case ConnectionTypeAzure: |
| 230 | + args := []string{"login", "--service-principal", "--username", c.Conn.Username, "--password", c.Conn.Password} |
| 231 | + if v, ok := c.Conn.Properties["tenant"]; ok { |
| 232 | + args = append(args, "--tenant") |
| 233 | + args = append(args, v) |
| 234 | + } |
| 235 | + |
| 236 | + // login with service principal |
| 237 | + runCmd := exec.CommandContext(ctx, "az", args...) |
| 238 | + if err := runCmd.Run(); err != nil { |
| 239 | + return err |
| 240 | + } |
| 241 | + } |
| 242 | + |
| 243 | + return nil |
| 244 | +} |
| 245 | + |
| 246 | +func saveConfig(content []byte, absPath string) error { |
| 247 | + file, err := os.Create(absPath) |
| 248 | + if err != nil { |
| 249 | + return err |
182 | 250 | }
|
| 251 | + defer file.Close() |
183 | 252 |
|
184 |
| - return envs, file.String() |
| 253 | + _, err = file.Write(content) |
| 254 | + return err |
185 | 255 | }
|
0 commit comments