I want to build a SFTP server which would take the file uploaded and directly upload it to azure blob
My SFTP server:
listener, err := net.Listen("tcp", ":2022")
if err != nil {
slog.ErrorContext(ctx, "Failed to listen on port: 2022", slog.Any(constants.Error, err))
return err
}
defer listener.Close()
for {
conn, err := listener.Accept()
if err != nil {
slog.ErrorContext(ctx, "Failed to accept incoming connection", slog.Any(constants.Error, err))
return err
}
privateKey := os.Getenv("PRIVATE_KEY")
serviceConfig := &ssh.ServerConfig{
NoClientAuth: true,
}
signer, err := ssh.ParsePrivateKey([]byte(privateKey))
if err != nil {
panic(err)
}
serviceConfig.AddHostKey(signer)
_, chans, req, err := ssh.NewServerConn(conn, serviceConfig)
if err != nil {
conn.Close()
slog.ErrorContext(ctx, "Failed to form new handshake", slog.Any(constants.Error, err))
return err
}
go ssh.DiscardRequests(req)
for newChannel := range chans {
if newChannel.ChannelType() != "session" {
newChannel.Reject(ssh.UnknownChannelType, "unknown channel type")
continue
}
channel, requests, err := newChannel.Accept()
if err != nil {
log.Fatal("could not accept channel.", err)
}
go func(in <-chan *ssh.Request) {
for req := range in {
ok := false
switch req.Type {
case "subsystem":
if string(req.Payload[4:]) == "sftp" {
ok = true
}
}
req.Reply(ok, nil)
}
}(requests)
server, err := sftp.NewServer(channel, []sftp.ServerOption{}...)
if err := server.Serve(); err != nil {
if err != io.EOF {
log.Fatal("sftp server completed with error:", err)
}
}
server.Close()
}
}
My blobStorage:
type BlobStorage interface {
Upload(ctx context.Context, key string, fileType model.FileType, fileContent []byte) error
}
// Storage represents dependency model for azure blob storage implementations.
type Storage struct {
blobURL string
pipeline pipeline.Pipeline
credential azblob.StorageAccountCredential
}
func (storage *Storage) Upload(ctx context.Context, key string, fileContent []byte) error {
u, _ := url.Parse(fmt.Sprintf("%s/%s", storage.blobURL, key))
slog.InfoContext(ctx, "blob url generated", slog.String("url", u.String()))
blockBlobURL := azblob.NewBlockBlobURL(*u, storage.pipeline)
options := azblob.UploadToBlockBlobOptions{
BlobHTTPHeaders: azblob.BlobHTTPHeaders{
ContentType: "text/csv",
},
}
_, err := azblob.UploadBufferToBlockBlob(ctx, fileContent, blockBlobURL, options)
if err != nil {
return err
}
slog.InfoContext(ctx, "successfully uploaded asset")
return nil
}
Is there a way to upload the file from client to SFTP then directly upload it to blob, without actually saving it in local, and same for download as well. Is there any way to do this?
I want to build a SFTP server which would take the file uploaded and directly upload it to azure blob
My SFTP server:
listener, err := net.Listen("tcp", ":2022")
if err != nil {
slog.ErrorContext(ctx, "Failed to listen on port: 2022", slog.Any(constants.Error, err))
return err
}
defer listener.Close()
for {
conn, err := listener.Accept()
if err != nil {
slog.ErrorContext(ctx, "Failed to accept incoming connection", slog.Any(constants.Error, err))
return err
}
privateKey := os.Getenv("PRIVATE_KEY")
serviceConfig := &ssh.ServerConfig{
NoClientAuth: true,
}
signer, err := ssh.ParsePrivateKey([]byte(privateKey))
if err != nil {
panic(err)
}
serviceConfig.AddHostKey(signer)
_, chans, req, err := ssh.NewServerConn(conn, serviceConfig)
if err != nil {
conn.Close()
slog.ErrorContext(ctx, "Failed to form new handshake", slog.Any(constants.Error, err))
return err
}
go ssh.DiscardRequests(req)
for newChannel := range chans {
if newChannel.ChannelType() != "session" {
newChannel.Reject(ssh.UnknownChannelType, "unknown channel type")
continue
}
channel, requests, err := newChannel.Accept()
if err != nil {
log.Fatal("could not accept channel.", err)
}
go func(in <-chan *ssh.Request) {
for req := range in {
ok := false
switch req.Type {
case "subsystem":
if string(req.Payload[4:]) == "sftp" {
ok = true
}
}
req.Reply(ok, nil)
}
}(requests)
server, err := sftp.NewServer(channel, []sftp.ServerOption{}...)
if err := server.Serve(); err != nil {
if err != io.EOF {
log.Fatal("sftp server completed with error:", err)
}
}
server.Close()
}
}
My blobStorage:
type BlobStorage interface {
Upload(ctx context.Context, key string, fileType model.FileType, fileContent []byte) error
}
// Storage represents dependency model for azure blob storage implementations.
type Storage struct {
blobURL string
pipeline pipeline.Pipeline
credential azblob.StorageAccountCredential
}
func (storage *Storage) Upload(ctx context.Context, key string, fileContent []byte) error {
u, _ := url.Parse(fmt.Sprintf("%s/%s", storage.blobURL, key))
slog.InfoContext(ctx, "blob url generated", slog.String("url", u.String()))
blockBlobURL := azblob.NewBlockBlobURL(*u, storage.pipeline)
options := azblob.UploadToBlockBlobOptions{
BlobHTTPHeaders: azblob.BlobHTTPHeaders{
ContentType: "text/csv",
},
}
_, err := azblob.UploadBufferToBlockBlob(ctx, fileContent, blockBlobURL, options)
if err != nil {
return err
}
slog.InfoContext(ctx, "successfully uploaded asset")
return nil
}
Is there a way to upload the file from client to SFTP then directly upload it to blob, without actually saving it in local, and same for download as well. Is there any way to do this?
Share Improve this question edited Jan 12 at 7:01 Steffen Ullrich 124k11 gold badges153 silver badges193 bronze badges asked Jan 12 at 4:46 Kaushal Kaushal 835 bronze badges 3- Refer to this link for Connect to Azure Blob Storage by using the SSH File Transfer Protocol (SFTP) – Sampath Commented Jan 13 at 9:23
- Are you using using ssh password/key? – Sampath Commented Jan 13 at 12:12
- @Sampath yes, i'm using ssh password and key – Kaushal Commented Jan 15 at 3:21
1 Answer
Reset to default 0How to integrate azure blobstorage to an SFTP server in golang
You can use the code below, which is currently used with the command in GoLang to upload files via an SFTP client.
In my environment, I created sftp client in the portal.
Portal:
Code:
package main
import (
"bytes"
"fmt"
"os/exec"
)
func main() {
// Prepare the SFTP command
cmd := exec.Command("sftp", "<storage account name>.<local user name>@<storage account name>.blob.core.windows")
// The file to upload
file := "xx"
// Send the `put` command using bytes.NewReader to wrap the byte slice into an io.Reader
cmd.Stdin = bytes.NewReader([]byte(fmt.Sprintf("put %s\n", file)))
// Execute the command and capture the output
output, err := cmd.CombinedOutput()
if err != nil {
fmt.Println("Error uploading file:", err)
return
}
// Print the result of the file upload
fmt.Println("File uploaded successfully:")
fmt.Println(string(output))
}
Output:
[email protected]'s password:
File uploaded successfully:
Connected to venkat8912.blob.core.windows.
sftp> put /sample5.pdf
Uploading sample5.pdf to /sample5.pdf