WIP: HTTP-01 solver that stores challenge tokens in FrostFS #4
4 changed files with 112 additions and 0 deletions
30
cmd/flags.go
30
cmd/flags.go
|
@ -29,6 +29,11 @@ const (
|
|||
flgHTTPWebroot = "http.webroot"
|
||||
flgHTTPMemcachedHost = "http.memcached-host"
|
||||
flgHTTPS3Bucket = "http.s3-bucket"
|
||||
flgHTTPFrostFSEndpoint = "http.frostfs-endpoint"
|
||||
flgHTTPFrostFSContainer = "http.frostfs-container"
|
||||
flgHTTPFrostFSWallet = "http.frostfs-wallet"
|
||||
flgHTTPFrostFSWalletAccount = "http.frostfs-wallet-account"
|
||||
flgHTTPFrostFSWalletPass = "http.frostfs-wallet-password"
|
||||
flgTLS = "tls"
|
||||
flgTLSPort = "tls.port"
|
||||
flgDNS = "dns"
|
||||
|
@ -135,6 +140,31 @@ func CreateFlags(defaultPath string) []cli.Flag {
|
|||
Name: flgHTTPS3Bucket,
|
||||
Usage: "Set the S3 bucket name to use for HTTP-01 based challenges. Challenges will be written to the S3 bucket.",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: flgHTTPFrostFSEndpoint,
|
||||
Usage: "Set FrostFS endpoint to use for HTTP-01 based challenges. Challenges will be written to FrostFS container",
|
||||
EnvVars: []string{"FROSTFS_ENDPOINT"},
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: flgHTTPFrostFSContainer,
|
||||
Usage: "Set FrostFS container ID to use for HTTP-01 based challenges. Challenges will be written to FrostFS container",
|
||||
EnvVars: []string{"FROSTFS_CONTAINER"},
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: flgHTTPFrostFSWallet,
|
||||
Usage: "Path to NEO wallet to use for interaction with FrostFS. If no wallet is provided an ephemeral one will be generated. Such key will only work for publicly writable containers and will significantly reduce security: any attacker with knowledge of FrostFS endpoint and CID will be able to obtain certificates for your domain",
|
||||
EnvVars: []string{"FROSTFS_WALLET"},
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: flgHTTPFrostFSWalletAccount,
|
||||
Usage: "Wallet account to use for interaction with FrostFS. If not set, the first account from wallet will be used",
|
||||
EnvVars: []string{"FROSTFS_WALLET_ACCOUNT"},
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: flgHTTPFrostFSWalletPass,
|
||||
Usage: "Account password to decrypt the wallet. If not set, an empty password is assumed",
|
||||
EnvVars: []string{"FROSTFS_WALLET_PASSWORD"},
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: flgTLS,
|
||||
Usage: "Use the TLS-ALPN-01 challenge to solve challenges. Can be mixed with other types of challenges.",
|
||||
|
|
|
@ -13,6 +13,7 @@ import (
|
|||
"github.com/go-acme/lego/v4/lego"
|
||||
"github.com/go-acme/lego/v4/log"
|
||||
"github.com/go-acme/lego/v4/providers/dns"
|
||||
"github.com/go-acme/lego/v4/providers/http/frostfs"
|
||||
"github.com/go-acme/lego/v4/providers/http/memcached"
|
||||
"github.com/go-acme/lego/v4/providers/http/s3"
|
||||
"github.com/go-acme/lego/v4/providers/http/webroot"
|
||||
|
@ -67,6 +68,18 @@ func setupHTTPProvider(ctx *cli.Context) challenge.Provider {
|
|||
log.Fatal(err)
|
||||
}
|
||||
return ps
|
||||
case ctx.IsSet(flgHTTPFrostFSEndpoint):
|
||||
ps, err := frostfs.NewHTTPProvider(
|
||||
ctx.String(flgHTTPFrostFSEndpoint),
|
||||
ctx.String(flgHTTPFrostFSContainer),
|
||||
ctx.String(flgHTTPFrostFSWallet),
|
||||
ctx.String(flgHTTPFrostFSWalletAccount),
|
||||
ctx.String(flgHTTPFrostFSWalletPass),
|
||||
)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
return ps
|
||||
case ctx.IsSet(flgHTTPPort):
|
||||
iface := ctx.String(flgHTTPPort)
|
||||
if !strings.Contains(iface, ":") {
|
||||
|
|
|
@ -36,6 +36,11 @@ GLOBAL OPTIONS:
|
|||
--http.webroot value Set the webroot folder to use for HTTP-01 based challenges to write directly to the .well-known/acme-challenge file. This disables the built-in server and expects the given directory to be publicly served with access to .well-known/acme-challenge
|
||||
--http.memcached-host value [ --http.memcached-host value ] Set the memcached host(s) to use for HTTP-01 based challenges. Challenges will be written to all specified hosts.
|
||||
--http.s3-bucket value Set the S3 bucket name to use for HTTP-01 based challenges. Challenges will be written to the S3 bucket.
|
||||
--http.frostfs-endpoint value Set FrostFS endpoint to use for HTTP-01 based challenges. Challenges will be written to FrostFS container [$FROSTFS_ENDPOINT]
|
||||
--http.frostfs-container value Set FrostFS container ID to use for HTTP-01 based challenges. Challenges will be written to FrostFS container [$FROSTFS_CONTAINER]
|
||||
--http.frostfs-wallet value Path to NEO wallet to use for interaction with FrostFS. If no wallet is provided an ephemeral one will be generated. Such key will only work for publicly writable containers and will significantly reduce security: any attacker with knowledge of FrostFS endpoint and CID will be able to obtain certificates for your domain [$FROSTFS_WALLET]
|
||||
--http.frostfs-wallet-account value Wallet account to use for interaction with FrostFS. If not set, the first account from wallet will be used [$FROSTFS_WALLET_ACCOUNT]
|
||||
--http.frostfs-wallet-password value Account password to decrypt the wallet. If not set, an empty password is assumed [$FROSTFS_WALLET_PASSWORD]
|
||||
--tls Use the TLS-ALPN-01 challenge to solve challenges. Can be mixed with other types of challenges. (default: false)
|
||||
--tls.port value Set the port and interface to use for TLS-ALPN-01 based challenges to listen on. Supported: interface:port or :port. (default: ":443")
|
||||
--dns value Solve a DNS-01 challenge using the specified provider. Can be mixed with other types of challenges. Run 'lego dnshelp' for help on usage.
|
||||
|
|
64
providers/http/frostfs/frostfs.go
Normal file
64
providers/http/frostfs/frostfs.go
Normal file
|
@ -0,0 +1,64 @@
|
|||
// Package frostfs provides HTTP-01 solver that saves challenge token to
|
||||
// FrostFS to make it available to multiple hosts at once.
|
||||
// Useful for deploying FrostFS gateways (HTTP or S3)
|
||||
package frostfs
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/go-acme/lego/v4/challenge"
|
||||
)
|
||||
|
||||
// HTTPProvider is a custom solver for HTTP-01 challenge that saves token to FrostFS.
|
||||
type HTTPProvider struct {
|
||||
frostfs *Storage
|
||||
oid string
|
||||
}
|
||||
|
||||
var _ challenge.Provider = new(HTTPProvider)
|
||||
|
||||
func NewHTTPProvider(endpoint, cid, walletPath, walletAccount, walletPassword string) (*HTTPProvider, error) {
|
||||
if endpoint == "" {
|
||||
return nil, errors.New("empty endpoint")
|
||||
}
|
||||
if cid == "" {
|
||||
return nil, errors.New("empty container id")
|
||||
}
|
||||
key, err := getKey(walletPath, walletAccount, walletPassword)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
storage, err := Open(endpoint, cid, key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &HTTPProvider{frostfs: storage}, nil
|
||||
}
|
||||
|
||||
func (w *HTTPProvider) Present(domain, token, keyAuth string) error {
|
||||
var err error
|
||||
if w.oid != "" {
|
||||
return fmt.Errorf("%T is not safe to re-enter: object was saved and not yet cleaned up: %s", w, w.oid)
|
||||
}
|
||||
w.oid, err = w.frostfs.Save(
|
||||
context.TODO(),
|
||||
[]byte(keyAuth),
|
||||
"FileName", token,
|
||||
"ACME", token,
|
||||
)
|
||||
return err
|
||||
}
|
||||
|
||||
func (w *HTTPProvider) CleanUp(domain, token, keyAuth string) error {
|
||||
if w.oid == "" {
|
||||
panic("Cleanup() called before Present()")
|
||||
}
|
||||
err := w.frostfs.Delete(context.TODO(), w.oid)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
w.oid = ""
|
||||
return nil
|
||||
}
|
Loading…
Reference in a new issue