Custom storage plugin help

Hello! I’m trying to write a plugin that extends the default FileStorage module to use less restrictive permissions. My use case is that I want to access Caddy’s certificates from another (non-root) app.

There was a thread about this recently (Certificate file permissions when sharing certificates), and I’m hoping that someone can help me with the practicalities of it – I’m new to Go!

I have a starting point as follows. With some logging, I can see that CertMagicStorage() and Store() are both called, and the resulting permissions are correct. My problem is that the files written by Store() aren’t in the root directory as defined in my Caddyfile (they’re written to the directory from which I started xcaddy).

It’s unclear to me how this root path is handled in certmagic’s own filestorage module. Maybe someone with some more Go experience can shed some light?

Caddyfile:

{
  storage permissive_file_storage {
    root "/home/tao/.caddy"
  }
  http_port 8080
  https_port 4443
}

localhost

Module code:

package permissivefilestorage

import (
	"io/ioutil"
	"log"
	"os"
	"path/filepath"

	"github.com/caddyserver/caddy/v2"
	"github.com/caddyserver/caddy/v2/modules/filestorage"
	"github.com/caddyserver/certmagic"
)

func init() {
	caddy.RegisterModule(PermissiveStorage{})
}

type CertmagicStorage struct {
	certmagic.FileStorage
	Path string
}

type PermissiveStorage struct {
	filestorage.FileStorage
}

func (PermissiveStorage) CaddyModule() caddy.ModuleInfo {
	return caddy.ModuleInfo{
		ID:  "caddy.storage.permissive_file_storage",
		New: func() caddy.Module { return new(PermissiveStorage) },
	}
}

// CertMagicStorage converts s to a certmagic.Storage instance.
func (s PermissiveStorage) CertMagicStorage() (certmagic.Storage, error) {
	// s.Root has the correct value from my Caddyfile
	return &CertmagicStorage{Path: s.Root}, nil
}

// Override Store to use globally-readable permissions
func (fs *CertmagicStorage) Store(key string, value []byte) error {
	filename := fs.Filename(key)
	err := os.MkdirAll(filepath.Dir(filename), 0755)
	if err != nil {
		return err
	}
	return ioutil.WriteFile(filename, value, 0644)
}
1 Like

I think I managed to work it out. In my custom certmagic.FileStorage struct, I had to initialize the Path field:

type CertmagicStorage struct {
	certmagic.FileStorage
}

// <snip>

func (s PermissiveStorage) CertMagicStorage() (certmagic.Storage, error) {
	return &CertmagicStorage{
		FileStorage: certmagic.FileStorage{
			Path: s.Root,
		},
	}, nil
}

Haven’t run this in production yet, but it seems to work.

1 Like

This topic was automatically closed after 60 days. New replies are no longer allowed.