diff --git a/README.md b/README.md index 013af14..a9706a9 100644 --- a/README.md +++ b/README.md @@ -53,6 +53,25 @@ active connections to close before shutting down. For additional options, use the `--help` flag. +## iRODS authentication + +Sqyrrl uses the standard iRODS environment file to authenticate to iRODS. If the user has been +authenticated with `iinit` before starting Sqyrrl, the server will use the existing iRODS auth +file created by `iinit`. If the user has not been authenticated, Sqyrrl will require the iRODS +password to be supplied using the environment variable `IRODS_PASSWORD`. Sqyrrl will then create +the iRODS auth file itself, without requiring `iinit` to be used. + +## Running in a container + +When running Sqyrrl in a Docker container, configuration files (iRODS environment file, SSL +certificates) should be mounted into the container and the password should be supplied using +the environment variable `IRODS_PASSWORD`. + +The docker-compose.yml file in the repository contains an example configuration for running +Sqyrrl in a container. + +```sh + ## Dependencies Sqyrrl uses [go-irodsclient](https://github.com/cyverse/go-irodsclient) to connect to iRODS. \ No newline at end of file diff --git a/config/.gitignore b/config/.gitignore new file mode 100644 index 0000000..e69de29 diff --git a/docker-compose.yml b/docker-compose.yml index e81f42c..f3089e7 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,19 +1,37 @@ version: "3" services: - irods-server: - container_name: irods-server - image: "ghcr.io/wtsi-npg/ub-16.04-irods-4.2.7:latest" - ports: - - "127.0.0.1:1247:1247" - - "127.0.0.1:20000-20199:20000-20199" - restart: always + irods-server: + container_name: irods-server + image: "ghcr.io/wtsi-npg/ub-16.04-irods-4.2.7:latest" + ports: + - "1247:1247" + - "20000-20199:20000-20199" + restart: always + healthcheck: + test: ["CMD", "nc", "-z", "-v", "localhost", "1247"] + start_period: 30s + interval: 5s + timeout: 10s + retries: 12 - app: - build: + app: + build: context: . dockerfile: Dockerfile - ports: - - "127.0.0.1:3333:3333" - depends_on: - - irods-server + command: ["start", + "--host", "0.0.0.0", + "--port", "3333", + "--cert-file", "/app/config/localhost.crt", + "--key-file", "/app/config/localhost.key", + "--irods-env", "/app/config/irods_environment.json", + "--log-level", "trace"] + environment: + IRODS_PASSWORD: "irods" + ports: + - "3333:3333" + volumes: + - ./config:/app/config + depends_on: + irods-server: + condition: service_healthy diff --git a/server/irods.go b/server/irods.go index 7989de9..6e55ff8 100644 --- a/server/irods.go +++ b/server/irods.go @@ -33,6 +33,7 @@ import ( const defaultIRODSEnvFile = "~/.irods/irods_environment.json" const iRODSEnvFileEnvVar = "IRODS_ENVIRONMENT_FILE" +const IRODSPasswordEnvVar = "IRODS_PASSWORD" const PublicUser = "public" @@ -59,13 +60,12 @@ func IRODSEnvFilePath() string { // InitIRODS initialises the iRODS environment by creating a populated auth file if it // does not already exist. This avoids the need to have `iinit` present on the server // host. -func InitIRODS(logger zerolog.Logger, manager *icommands.ICommandsEnvironmentManager, password string) error { - authFile := manager.GetPasswordFilePath() - if _, err := os.Stat(authFile); err != nil && errors.Is(err, os.ErrNotExist) { +func InitIRODS(logger zerolog.Logger, authFilePath string, password string) error { + if _, err := os.Stat(authFilePath); err != nil && errors.Is(err, os.ErrNotExist) { logger.Info(). - Str("path", authFile). + Str("path", authFilePath). Msg("Creating an iRODS auth file because one does not exist") - return icommands.EncodePasswordFile(authFile, password, os.Getuid()) + return icommands.EncodePasswordFile(authFilePath, password, os.Getuid()) } return nil } @@ -117,11 +117,36 @@ func NewIRODSAccount(logger zerolog.Logger, return nil, err } + password, ok := os.LookupEnv(IRODSPasswordEnvVar) + if !ok { + logger.Error(). + Str("variable", IRODSPasswordEnvVar). + Msg("Environment variable not set") + return nil, errors.New("the iRODS password environment variable was not set") + } + if password == "" { + logger.Error(). + Str("variable", IRODSPasswordEnvVar). + Msg("Environment variable empty") + return nil, errors.New("the iRODS password environment variable was empty") + } + account.Password = password + + authFilePath := manager.GetPasswordFilePath() + if err = InitIRODS(logger, authFilePath, password); err != nil { + logger.Err(err). + Str("path", authFilePath). + Msg("Failed to initialise iRODS") + return nil, err + } + logger.Info(). Str("host", account.Host). Int("port", account.Port). Str("zone", account.ClientZone). Str("user", account.ClientUser). + Str("env_file", manager.GetEnvironmentFilePath()). + Str("auth_file", manager.GetPasswordFilePath()). Str("auth_scheme", string(account.AuthenticationScheme)). Bool("cs_neg_required", account.ClientServerNegotiation). Str("cs_neg_policy", string(account.CSNegotiationPolicy)). diff --git a/server/server_suite_test.go b/server/server_suite_test.go index 0a7b0eb..1efd6e9 100644 --- a/server/server_suite_test.go +++ b/server/server_suite_test.go @@ -63,7 +63,10 @@ var _ = BeforeSuite(func() { err = manager.SetEnvironmentFilePath(iRODSEnvFile) Expect(err).NotTo(HaveOccurred()) - err = server.InitIRODS(suiteLogger, manager, "irods") + err = os.Setenv(server.IRODSPasswordEnvVar, "irods") + Expect(err).NotTo(HaveOccurred()) + authFilePath := manager.GetPasswordFilePath() + err = server.InitIRODS(suiteLogger, authFilePath, os.Getenv(server.IRODSPasswordEnvVar)) Expect(err).NotTo(HaveOccurred()) account, err = server.NewIRODSAccount(suiteLogger, manager)