Skip to content

Commit

Permalink
add putparameter
Browse files Browse the repository at this point in the history
  • Loading branch information
leneffets committed Nov 18, 2024
1 parent 20c6b6d commit f4778c5
Show file tree
Hide file tree
Showing 2 changed files with 206 additions and 144 deletions.
20 changes: 18 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# SSM and S3 Server

This project provides an HTTP server using Go, which interacts with AWS Systems Manager (SSM) to fetch parameters and with S3 to fetch files. This project is useful for running a sidecar, to use original images without a hassle.
This project provides an HTTP server using Go, which interacts with AWS Systems Manager (SSM) to fetch/put parameters and with S3 to fetch/put files. This project is useful for running a sidecar, to use original images without a hassle.
The server exposes two main endpoints: `/ssm` and `/s3`.

## Features
Expand Down Expand Up @@ -58,6 +58,22 @@ Fetch a decrypted parameter from AWS SSM.
curl "http://localhost:3000/ssm?name=example_parameter"
```

### Put SSM Parameter

Put a parameter to AWS SSM.

- **URL:** `/ssm`
- **Method:** `POST`
- **Query Parameters:**
- `name`: Name of the SSM parameter to put.
- `value`: Value of the SSM parameter to put.
- `type`: Type of the SSM parameter to put. (String, SecureString)
- **Example:**

```sh
curl -X POST -d "name=/path/to/parameter&value=somevalue&type=String" http://localhost:3000/ssm
```

### Fetch S3 File

Fetch a file from an S3 bucket.
Expand All @@ -73,7 +89,7 @@ Fetch a file from an S3 bucket.
curl "http://localhost:3000/s3?bucket=example-bucket&key=example-key"
```

### Fetch S3 File
### Upload S3 File

Upload a file to an S3 bucket.

Expand Down
330 changes: 188 additions & 142 deletions cmd/server/main.go
Original file line number Diff line number Diff line change
@@ -1,161 +1,207 @@
package main

import (
"context"
"io"
"io/ioutil"
"log"
"net/http"
"os"
"time"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/s3"
"github.com/aws/aws-sdk-go/service/ssm"
"github.com/aws/aws-sdk-go/service/ssm/ssmiface"
"context"
"io"
"io/ioutil"
"log"
"net/http"
"os"
"time"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/s3"
"github.com/aws/aws-sdk-go/service/ssm"
"github.com/aws/aws-sdk-go/service/ssm/ssmiface"
)

// Funktion, um SSM-Parameter abzurufen
func GetParameter(ctx context.Context, svc ssmiface.SSMAPI, name *string) (*ssm.GetParameterOutput, error) {
results, err := svc.GetParameterWithContext(ctx, &ssm.GetParameterInput{
Name: name,
WithDecryption: aws.Bool(true),
})
return results, err
results, err := svc.GetParameterWithContext(ctx, &ssm.GetParameterInput{
Name: name,
WithDecryption: aws.Bool(true),
})
return results, err
}

// Funktion, um ein Objekt aus S3 zu holen
func GetFromS3(ctx context.Context, sess *session.Session, bucket, key string) (io.ReadCloser, error) {
svc := s3.New(sess)
output, err := svc.GetObjectWithContext(ctx, &s3.GetObjectInput{
Bucket: aws.String(bucket),
Key: aws.String(key),
})
if err != nil {
return nil, err
}
return output.Body, nil
svc := s3.New(sess)
output, err := svc.GetObjectWithContext(ctx, &s3.GetObjectInput{
Bucket: aws.String(bucket),
Key: aws.String(key),
})
if err != nil {
return nil, err
}
return output.Body, nil
}

// Funktion, um ein Objekt in S3 zu legen
func PutToS3(ctx context.Context, sess *session.Session, bucket, key string, body io.ReadSeeker) error {
svc := s3.New(sess)
_, err := svc.PutObjectWithContext(ctx, &s3.PutObjectInput{
Bucket: aws.String(bucket),
Key: aws.String(key),
Body: body,
})
return err
svc := s3.New(sess)
_, err := svc.PutObjectWithContext(ctx, &s3.PutObjectInput{
Bucket: aws.String(bucket),
Key: aws.String(key),
Body: body,
})
return err
}

// Funktion, um einen Parameter in den Parameter Store zu legen
func PutParameter(ctx context.Context, svc ssmiface.SSMAPI, name *string, value *string, typeStr *string) (*ssm.PutParameterOutput, error) {
results, err := svc.PutParameterWithContext(ctx, &ssm.PutParameterInput{
Name: name,
Value: value,
Type: aws.String(*typeStr),
})
return results, err
}

func main() {
sess := session.Must(session.NewSessionWithOptions(session.Options{
SharedConfigState: session.SharedConfigEnable,
}))

svc := ssm.New(sess)

creds, err := sess.Config.Credentials.Get()
if err != nil {
log.Fatalf("Failed to get credentials: %v", err)
}
log.Printf("Using credentials: %s/%s\n", creds.AccessKeyID, creds.SecretAccessKey)

http.HandleFunc("/ssm", func(w http.ResponseWriter, r *http.Request) {
// Validate input parameter
id := r.URL.Query().Get("name")
if id == "" {
http.Error(w, "Parameter 'name' is required", http.StatusBadRequest)
return
}

// Set context with timeout
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()

// Fetch parameter
results, err := GetParameter(ctx, svc, &id)
if err != nil {
log.Printf("Error fetching parameter: %v", err)
http.Error(w, "Error fetching parameter", http.StatusInternalServerError)
return
}

w.Header().Set("Content-Type", "text/plain")
w.Write([]byte(*results.Parameter.Value))
})

http.HandleFunc("/s3", func(w http.ResponseWriter, r *http.Request) {
bucket := r.URL.Query().Get("bucket")
key := r.URL.Query().Get("key")
if bucket == "" || key == "" {
http.Error(w, "Parameters 'bucket' and 'key' are required", http.StatusBadRequest)
return
}

ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()

if r.Method == http.MethodGet {
body, err := GetFromS3(ctx, sess, bucket, key)
if err != nil {
http.Error(w, "Error fetching file from S3", http.StatusInternalServerError)
log.Printf("Error fetching file from S3: %v", err)
return
}
defer body.Close()

w.Header().Set("Content-Type", "application/octet-stream")
if _, err := io.Copy(w, body); err != nil {
http.Error(w, "Error sending file", http.StatusInternalServerError)
log.Printf("Error sending file: %v", err)
return
}
} else if r.Method == http.MethodPost {
file, _, err := r.FormFile("file")
if err != nil {
http.Error(w, "Error reading uploaded file", http.StatusBadRequest)
log.Printf("Error reading uploaded file: %v", err)
return
}
defer file.Close()

tempFile, err := ioutil.TempFile("", "upload-*.tmp")
if err != nil {
http.Error(w, "Error creating temporary file", http.StatusInternalServerError)
log.Printf("Error creating temporary file: %v", err)
return
}
defer os.Remove(tempFile.Name())

if _, err := io.Copy(tempFile, file); err != nil {
http.Error(w, "Error saving file", http.StatusInternalServerError)
log.Printf("Error saving file: %v", err)
return
}

tempFile.Seek(0, 0)

if err := PutToS3(ctx, sess, bucket, key, tempFile); err != nil {
http.Error(w, "Error uploading file to S3", http.StatusInternalServerError)
log.Printf("Error uploading file to S3: %v", err)
return
}

w.WriteHeader(http.StatusOK)
log.Printf("File uploaded successfully to bucket %s with key %s", bucket, key)
} else {
http.Error(w, "Invalid method", http.StatusMethodNotAllowed)
}
})

port := os.Getenv("PORT")
if port == "" {
port = "3000"
}

log.Printf("Server running on port %s", port)
if err := http.ListenAndServe(":" + port, nil); err != nil {
log.Fatalf("Error starting server: %v", err)
}
sess := session.Must(session.NewSessionWithOptions(session.Options{
SharedConfigState: session.SharedConfigEnable,
}))

svc := ssm.New(sess)

creds, err := sess.Config.Credentials.Get()
if err != nil {
log.Fatalf("Failed to get credentials: %v", err)
}
log.Printf("Using credentials: %s/%s\n", creds.AccessKeyID, creds.SecretAccessKey)

http.HandleFunc("/ssm", func(w http.ResponseWriter, r *http.Request) {
if r.Method == http.MethodGet {
// Validate input parameter
id := r.URL.Query().Get("name")
if id == "" {
http.Error(w, "Parameter 'name' is required", http.StatusBadRequest)
return
}

// Set context with timeout
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()

// Fetch parameter
results, err := GetParameter(ctx, svc, &id)
if err != nil {
log.Printf("Error fetching parameter: %v", err)
http.Error(w, "Error fetching parameter", http.StatusInternalServerError)
return
}

w.Header().Set("Content-Type", "text/plain")
w.Write([]byte(*results.Parameter.Value))
} else if r.Method == http.MethodPost {
// Parse the form data
if err := r.ParseForm(); err != nil {
http.Error(w, "Invalid form data", http.StatusBadRequest)
log.Printf("Invalid form data: %v", err)
return
}

// Validate input parameters
name := r.FormValue("name")
value := r.FormValue("value")
typeStr := r.FormValue("type")

if name == "" || value == "" || typeStr == "" {
http.Error(w, "Parameters 'name', 'value', and 'type' are required", http.StatusBadRequest)
return
}

// Set context with timeout
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()

// Put parameter
_, err := PutParameter(ctx, svc, &name, &value, &typeStr)
if err != nil {
http.Error(w, "Error putting parameter", http.StatusInternalServerError)
log.Printf("Error putting parameter: %v", err)
return
}

log.Printf("Parameter %s uploaded successfully", name)
w.WriteHeader(http.StatusOK)
} else {
http.Error(w, "Invalid method", http.StatusMethodNotAllowed)
}
})

http.HandleFunc("/s3", func(w http.ResponseWriter, r *http.Request) {
bucket := r.URL.Query().Get("bucket")
key := r.URL.Query().Get("key")
if bucket == "" || key == "" {
http.Error(w, "Parameters 'bucket' and 'key' are required", http.StatusBadRequest)
return
}

ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()

if r.Method == http.MethodGet {
body, err := GetFromS3(ctx, sess, bucket, key)
if err != nil {
http.Error(w, "Error fetching file from S3", http.StatusInternalServerError)
log.Printf("Error fetching file from S3: %v", err)
return
}
defer body.Close()

w.Header().Set("Content-Type", "application/octet-stream")
if _, err := io.Copy(w, body); err != nil {
http.Error(w, "Error sending file", http.StatusInternalServerError)
log.Printf("Error sending file: %v", err)
return
}
} else if r.Method == http.MethodPost {
file, _, err := r.FormFile("file")
if err != nil {
http.Error(w, "Error reading uploaded file", http.StatusBadRequest)
log.Printf("Error reading uploaded file: %v", err)
return
}
defer file.Close()

tempFile, err := ioutil.TempFile("", "upload-*.tmp")
if err != nil {
http.Error(w, "Error creating temporary file", http.StatusInternalServerError)
log.Printf("Error creating temporary file: %v", err)
return
}
defer os.Remove(tempFile.Name())

if _, err := io.Copy(tempFile, file); err != nil {
http.Error(w, "Error saving file", http.StatusInternalServerError)
log.Printf("Error saving file: %v", err)
return
}

tempFile.Seek(0, 0)

if err := PutToS3(ctx, sess, bucket, key, tempFile); err != nil {
http.Error(w, "Error uploading file to S3", http.StatusInternalServerError)
log.Printf("Error uploading file to S3: %v", err)
return
}

log.Printf("File uploaded successfully to bucket %s with key %s", bucket, key)
w.WriteHeader(http.StatusOK)
} else {
http.Error(w, "Invalid method", http.StatusMethodNotAllowed)
}
})

port := os.Getenv("PORT")
if port == "" {
port = "3000"
}

log.Printf("Server running on port %s", port)
if err := http.ListenAndServe(":"+port, nil); err != nil {
log.Fatalf("Error starting server: %v", err)
}
}

0 comments on commit f4778c5

Please sign in to comment.