koji: add config files to configure kerberos settings
Kerberos keytabs and principals are configured per koji server both in composer and in the worker. Signed-off-by: Tom Gundersen <teg@jklm.no>
This commit is contained in:
parent
9666be2891
commit
c6cf9de85d
6 changed files with 129 additions and 17 deletions
|
|
@ -9,11 +9,13 @@ import (
|
|||
"os"
|
||||
"path"
|
||||
|
||||
"github.com/BurntSushi/toml"
|
||||
"github.com/osbuild/osbuild-composer/internal/distro/fedora31"
|
||||
"github.com/osbuild/osbuild-composer/internal/distro/fedora32"
|
||||
"github.com/osbuild/osbuild-composer/internal/distro/rhel8"
|
||||
"github.com/osbuild/osbuild-composer/internal/jobqueue/fsjobqueue"
|
||||
"github.com/osbuild/osbuild-composer/internal/kojiapi"
|
||||
"github.com/osbuild/osbuild-composer/internal/upload/koji"
|
||||
|
||||
"github.com/osbuild/osbuild-composer/internal/common"
|
||||
"github.com/osbuild/osbuild-composer/internal/distro"
|
||||
|
|
@ -25,6 +27,8 @@ import (
|
|||
"github.com/coreos/go-systemd/activation"
|
||||
)
|
||||
|
||||
const configFile = "/etc/osbuild-composer/osbuild-composer.toml"
|
||||
|
||||
type connectionConfig struct {
|
||||
CACertFile string
|
||||
ServerKeyFile string
|
||||
|
|
@ -55,10 +59,30 @@ func createTLSConfig(c *connectionConfig) (*tls.Config, error) {
|
|||
}
|
||||
|
||||
func main() {
|
||||
var config struct {
|
||||
KojiServers map[string]struct {
|
||||
Kerberos *struct {
|
||||
Principal string `toml:"principal"`
|
||||
KeyTab string `toml:"keytab"`
|
||||
} `toml:"kerberos,omitempty"`
|
||||
} `toml:"koji"`
|
||||
}
|
||||
var verbose bool
|
||||
flag.BoolVar(&verbose, "v", false, "Print access log")
|
||||
flag.Parse()
|
||||
|
||||
_, err := toml.DecodeFile(configFile, &config)
|
||||
if err == nil {
|
||||
log.Println("Composer configuration:")
|
||||
encoder := toml.NewEncoder(log.Writer())
|
||||
err := encoder.Encode(&config)
|
||||
if err != nil {
|
||||
log.Fatalf("Could not print config: %v", err)
|
||||
}
|
||||
} else if !os.IsNotExist(err) {
|
||||
log.Fatalf("Could not load config file '%s': %v", configFile, err)
|
||||
}
|
||||
|
||||
stateDir, ok := os.LookupEnv("STATE_DIRECTORY")
|
||||
if !ok {
|
||||
log.Fatal("STATE_DIRECTORY is not set. Is the service file missing StateDirectory=?")
|
||||
|
|
@ -151,7 +175,19 @@ func main() {
|
|||
|
||||
// Optionally run Koji API
|
||||
if kojiListeners, exists := listeners["osbuild-composer-koji.socket"]; exists {
|
||||
kojiServer := kojiapi.NewServer(workers, rpm, distros)
|
||||
kojiServers := make(map[string]koji.GSSAPICredentials)
|
||||
for server, creds := range config.KojiServers {
|
||||
if creds.Kerberos == nil {
|
||||
// For now we only support Kerberos authentication.
|
||||
continue
|
||||
}
|
||||
kojiServers[server] = koji.GSSAPICredentials{
|
||||
Principal: creds.Kerberos.Principal,
|
||||
KeyTab: creds.Kerberos.KeyTab,
|
||||
}
|
||||
}
|
||||
|
||||
kojiServer := kojiapi.NewServer(workers, rpm, distros, kojiServers)
|
||||
|
||||
tlsConfig, err := createTLSConfig(&connectionConfig{
|
||||
CACertFile: "/etc/osbuild-composer/ca-crt.pem",
|
||||
|
|
|
|||
|
|
@ -10,10 +10,12 @@ import (
|
|||
"io/ioutil"
|
||||
"log"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"path"
|
||||
"time"
|
||||
|
||||
"github.com/BurntSushi/toml"
|
||||
"github.com/google/uuid"
|
||||
|
||||
"github.com/osbuild/osbuild-composer/internal/common"
|
||||
|
|
@ -26,6 +28,8 @@ import (
|
|||
"github.com/osbuild/osbuild-composer/internal/worker"
|
||||
)
|
||||
|
||||
const configFile = "/etc/osbuild-worker/osbuild-worker.toml"
|
||||
|
||||
type connectionConfig struct {
|
||||
CACertFile string
|
||||
ClientKeyFile string
|
||||
|
|
@ -92,7 +96,7 @@ func osbuildStagesToRPMs(stages []osbuild.StageResult) []koji.RPM {
|
|||
return rpms
|
||||
}
|
||||
|
||||
func RunJob(job worker.Job, store string) (*osbuild.Result, error) {
|
||||
func RunJob(job worker.Job, store string, kojiServers map[string]koji.GSSAPICredentials) (*osbuild.Result, error) {
|
||||
outputDirectory, err := ioutil.TempDir("/var/tmp", "osbuild-worker-*")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error creating temporary output directory: %v", err)
|
||||
|
|
@ -201,7 +205,13 @@ func RunJob(job worker.Job, store string) (*osbuild.Result, error) {
|
|||
Renegotiation: tls.RenegotiateOnceAsClient,
|
||||
}
|
||||
|
||||
k, err := koji.NewFromGSSAPI(options.Server, &koji.GSSAPICredentials{}, transport)
|
||||
kojiServer, _ := url.Parse(options.Server)
|
||||
creds, exists := kojiServers[kojiServer.Hostname()]
|
||||
if !exists {
|
||||
r = append(r, fmt.Errorf("Koji server has not been configured: %s", kojiServer.Hostname()))
|
||||
}
|
||||
|
||||
k, err := koji.NewFromGSSAPI(options.Server, &creds, transport)
|
||||
if err != nil {
|
||||
r = append(r, err)
|
||||
continue
|
||||
|
|
@ -294,7 +304,7 @@ func RunJob(job worker.Job, store string) (*osbuild.Result, error) {
|
|||
return result, nil
|
||||
}
|
||||
|
||||
func FailJob(job worker.Job) {
|
||||
func FailJob(job worker.Job, kojiServers map[string]koji.GSSAPICredentials) {
|
||||
_, targets, err := job.OSBuildArgs()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
|
|
@ -310,7 +320,14 @@ func FailJob(job worker.Job) {
|
|||
Renegotiation: tls.RenegotiateOnceAsClient,
|
||||
}
|
||||
|
||||
k, err := koji.NewFromGSSAPI(options.Server, &koji.GSSAPICredentials{}, transport)
|
||||
kojiServer, _ := url.Parse(options.Server)
|
||||
creds, exists := kojiServers[kojiServer.Hostname()]
|
||||
if !exists {
|
||||
log.Printf("Koji server has not been configured: %s", kojiServer.Hostname())
|
||||
return
|
||||
}
|
||||
|
||||
k, err := koji.NewFromGSSAPI(options.Server, &creds, transport)
|
||||
if err != nil {
|
||||
log.Printf("koji login failed: %v", err)
|
||||
return
|
||||
|
|
@ -357,6 +374,14 @@ func WatchJob(ctx context.Context, job worker.Job) {
|
|||
}
|
||||
|
||||
func main() {
|
||||
var config struct {
|
||||
KojiServers map[string]struct {
|
||||
Kerberos *struct {
|
||||
Principal string `toml:"principal"`
|
||||
KeyTab string `toml:"keytab"`
|
||||
} `toml:"kerberos,omitempty"`
|
||||
} `toml:"koji"`
|
||||
}
|
||||
var unix bool
|
||||
flag.BoolVar(&unix, "unix", false, "Interpret 'address' as a path to a unix domain socket instead of a network address")
|
||||
|
||||
|
|
@ -373,12 +398,36 @@ func main() {
|
|||
flag.Usage()
|
||||
}
|
||||
|
||||
_, err := toml.DecodeFile(configFile, &config)
|
||||
if err == nil {
|
||||
log.Println("Composer configuration:")
|
||||
encoder := toml.NewEncoder(log.Writer())
|
||||
err := encoder.Encode(&config)
|
||||
if err != nil {
|
||||
log.Fatalf("Could not print config: %v", err)
|
||||
}
|
||||
} else if !os.IsNotExist(err) {
|
||||
log.Fatalf("Could not load config file '%s': %v", configFile, err)
|
||||
}
|
||||
|
||||
cacheDirectory, ok := os.LookupEnv("CACHE_DIRECTORY")
|
||||
if !ok {
|
||||
log.Fatal("CACHE_DIRECTORY is not set. Is the service file missing CacheDirectory=?")
|
||||
}
|
||||
store := path.Join(cacheDirectory, "osbuild-store")
|
||||
|
||||
kojiServers := make(map[string]koji.GSSAPICredentials)
|
||||
for server, creds := range config.KojiServers {
|
||||
if creds.Kerberos == nil {
|
||||
// For now we only support Kerberos authentication.
|
||||
continue
|
||||
}
|
||||
kojiServers[server] = koji.GSSAPICredentials{
|
||||
Principal: creds.Kerberos.Principal,
|
||||
KeyTab: creds.Kerberos.KeyTab,
|
||||
}
|
||||
}
|
||||
|
||||
var client *worker.Client
|
||||
if unix {
|
||||
client = worker.NewClientUnix(address)
|
||||
|
|
@ -411,13 +460,13 @@ func main() {
|
|||
go WatchJob(ctx, job)
|
||||
|
||||
var status common.ImageBuildState
|
||||
result, err := RunJob(job, store)
|
||||
result, err := RunJob(job, store, kojiServers)
|
||||
if err != nil {
|
||||
log.Printf(" Job failed: %v", err)
|
||||
status = common.IBFailed
|
||||
|
||||
// Fail the jobs in any targets that expects it
|
||||
FailJob(job)
|
||||
FailJob(job, kojiServers)
|
||||
|
||||
// If the error comes from osbuild, retrieve the result
|
||||
if osbuildError, ok := err.(*OSBuildError); ok {
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import (
|
|||
"log"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/osbuild/osbuild-composer/internal/blueprint"
|
||||
|
|
@ -26,14 +27,16 @@ type Server struct {
|
|||
workers *worker.Server
|
||||
rpmMetadata rpmmd.RPMMD
|
||||
distros *distro.Registry
|
||||
kojiServers map[string]koji.GSSAPICredentials
|
||||
}
|
||||
|
||||
// NewServer creates a new koji server
|
||||
func NewServer(workers *worker.Server, rpmMetadata rpmmd.RPMMD, distros *distro.Registry) *Server {
|
||||
func NewServer(workers *worker.Server, rpmMetadata rpmmd.RPMMD, distros *distro.Registry, kojiServers map[string]koji.GSSAPICredentials) *Server {
|
||||
server := &Server{
|
||||
workers: workers,
|
||||
rpmMetadata: rpmMetadata,
|
||||
distros: distros,
|
||||
kojiServers: kojiServers,
|
||||
}
|
||||
return server
|
||||
}
|
||||
|
|
@ -71,6 +74,18 @@ func (server *Server) PostCompose(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
kojiServer, err := url.Parse(request.Koji.Server)
|
||||
if err != nil {
|
||||
http.Error(w, fmt.Sprintf("Invalid Koji server: %s", request.Koji.Server), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
creds, exists := server.kojiServers[kojiServer.Hostname()]
|
||||
if !exists {
|
||||
http.Error(w, fmt.Sprintf("Koji server has not been configured: %s", kojiServer.Hostname()), http.StatusBadRequest)
|
||||
return
|
||||
|
||||
}
|
||||
|
||||
type imageRequest struct {
|
||||
manifest distro.Manifest
|
||||
filename string
|
||||
|
|
@ -137,7 +152,7 @@ func (server *Server) PostCompose(w http.ResponseWriter, r *http.Request) {
|
|||
Renegotiation: tls.RenegotiateOnceAsClient,
|
||||
}
|
||||
|
||||
k, err := koji.NewFromGSSAPI(request.Koji.Server, &koji.GSSAPICredentials{}, transport)
|
||||
k, err := koji.NewFromGSSAPI(request.Koji.Server, &creds, transport)
|
||||
if err != nil {
|
||||
http.Error(w, fmt.Sprintf("Could not log into Koji: %v", err), http.StatusBadRequest)
|
||||
return
|
||||
|
|
|
|||
|
|
@ -36,31 +36,37 @@ fi
|
|||
greenprint "Starting containers"
|
||||
sudo ./internal/upload/koji/run-koji-container.sh start
|
||||
|
||||
greenprint "Copying custom composer/worker config"
|
||||
sudo mkdir -p /etc/osbuild-composer
|
||||
sudo cp test/image-tests/osbuild-composer.toml \
|
||||
/etc/osbuild-composer/
|
||||
sudo mkdir -p /etc/osbuild-worker
|
||||
sudo cp test/image-tests/osbuild-worker.toml \
|
||||
/etc/osbuild-worker/
|
||||
|
||||
greenprint "Adding kerberos config"
|
||||
sudo cp \
|
||||
/tmp/osbuild-composer-koji-test/client.keytab \
|
||||
/etc/krb5.keytab
|
||||
/etc/osbuild-composer/client.keytab
|
||||
sudo cp \
|
||||
/tmp/osbuild-composer-koji-test/client.keytab \
|
||||
/etc/osbuild-worker/client.keytab
|
||||
sudo cp \
|
||||
test/image-tests/krb5-local.conf \
|
||||
/etc/krb5.conf.d/local
|
||||
|
||||
greenprint "Initializing Kerberos"
|
||||
kinit osbuild-krb@LOCAL -k
|
||||
sudo -u _osbuild-composer kinit osbuild-krb@LOCAL -k
|
||||
|
||||
greenprint "Adding generated CA cert for Koji"
|
||||
sudo cp \
|
||||
/tmp/osbuild-composer-koji-test/ca-crt.pem \
|
||||
/etc/pki/ca-trust/source/anchors/koji-ca-crt.pem
|
||||
sudo update-ca-trust
|
||||
|
||||
greenprint "Restarting composer to pick up new certs"
|
||||
greenprint "Restarting composer to pick up new config"
|
||||
sudo systemctl restart osbuild-composer
|
||||
sudo systemctl restart osbuild-worker\@1
|
||||
|
||||
greenprint "Testing Koji"
|
||||
koji --server=http://localhost/kojihub --user=osbuild --password=osbuildpass --authtype=password hello
|
||||
koji --server=http://localhost/kojihub hello
|
||||
sudo -u _osbuild-composer koji --server=http://localhost/kojihub hello
|
||||
|
||||
greenprint "Creating Koji task"
|
||||
koji --server=http://localhost/kojihub --user kojiadmin --password kojipass --authtype=password make-task image
|
||||
|
|
|
|||
3
test/image-tests/osbuild-composer.toml
Normal file
3
test/image-tests/osbuild-composer.toml
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
[koji.localhost.kerberos]
|
||||
principal = "osbuild-krb@LOCAL"
|
||||
keytab = "/etc/osbuild-composer/client.keytab"
|
||||
3
test/image-tests/osbuild-worker.toml
Normal file
3
test/image-tests/osbuild-worker.toml
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
[koji.localhost.kerberos]
|
||||
principal = "osbuild-krb@LOCAL"
|
||||
keytab = "/etc/osbuild-worker/client.keytab"
|
||||
Loading…
Add table
Add a link
Reference in a new issue