mirror of
https://github.com/pgsty/minio.git
synced 2026-11-04 14:52:02 +03:00
Compare commits
9 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 586614c73f | |||
| d140074773 | |||
| 39face27cf | |||
| e047ac52b8 | |||
| 04de3ea4bd | |||
| e6ce9da087 | |||
| c9c0d5eec2 | |||
| 63c3114657 | |||
| 63ac1d6d18 |
@@ -17,7 +17,8 @@ docker run -p 9000:9000 minio/minio server /data
|
||||
docker pull minio/minio:edge
|
||||
docker run -p 9000:9000 minio/minio:edge server /data
|
||||
```
|
||||
Note: Docker will not display the default keys unless you start the container with the `-it`(interactive TTY) argument. Generally, it is not recommended to use default keys with containers. Please visit MinIO Docker quickstart guide for more information [here](https://docs.min.io/docs/minio-docker-quickstart-guide)
|
||||
|
||||
> NOTE: Docker will not display the default keys unless you start the container with the `-it`(interactive TTY) argument. Generally, it is not recommended to use default keys with containers. Please visit MinIO Docker quickstart guide for more information [here](https://docs.min.io/docs/minio-docker-quickstart-guide)
|
||||
|
||||
## macOS
|
||||
### Homebrew
|
||||
@@ -34,8 +35,8 @@ brew install minio/stable/minio
|
||||
```
|
||||
|
||||
### Binary Download
|
||||
| Platform | Architecture | URL |
|
||||
| ---------- | -------- | ------ |
|
||||
| Platform | Architecture | URL |
|
||||
| ---------- | -------- | ------ |
|
||||
| Apple macOS | 64-bit Intel | https://dl.min.io/server/minio/release/darwin-amd64/minio |
|
||||
```sh
|
||||
chmod 755 minio
|
||||
@@ -44,8 +45,8 @@ chmod 755 minio
|
||||
|
||||
## GNU/Linux
|
||||
### Binary Download
|
||||
| Platform | Architecture | URL |
|
||||
| ---------- | -------- | ------ |
|
||||
| Platform | Architecture | URL |
|
||||
| ---------- | -------- | ------ |
|
||||
| GNU/Linux | 64-bit Intel | https://dl.min.io/server/minio/release/linux-amd64/minio |
|
||||
```sh
|
||||
wget https://dl.min.io/server/minio/release/linux-amd64/minio
|
||||
@@ -53,8 +54,8 @@ chmod +x minio
|
||||
./minio server /data
|
||||
```
|
||||
|
||||
| Platform | Architecture | URL |
|
||||
| ---------- | -------- | ------ |
|
||||
| Platform | Architecture | URL |
|
||||
| ---------- | -------- | ------ |
|
||||
| GNU/Linux | ppc64le | https://dl.min.io/server/minio/release/linux-ppc64le/minio |
|
||||
```sh
|
||||
wget https://dl.min.io/server/minio/release/linux-ppc64le/minio
|
||||
@@ -64,8 +65,8 @@ chmod +x minio
|
||||
|
||||
## Microsoft Windows
|
||||
### Binary Download
|
||||
| Platform | Architecture | URL |
|
||||
| ---------- | -------- | ------ |
|
||||
| Platform | Architecture | URL |
|
||||
| ---------- | -------- | ------ |
|
||||
| Microsoft Windows | 64-bit | https://dl.min.io/server/minio/release/windows-amd64/minio.exe |
|
||||
```sh
|
||||
minio.exe server D:\Photos
|
||||
|
||||
@@ -69,6 +69,16 @@ func (a adminAPIHandlers) RemoveUser(w http.ResponseWriter, r *http.Request) {
|
||||
vars := mux.Vars(r)
|
||||
accessKey := vars["accessKey"]
|
||||
|
||||
ok, err := globalIAMSys.IsTempUser(accessKey)
|
||||
if err != nil {
|
||||
writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL)
|
||||
return
|
||||
}
|
||||
if ok {
|
||||
writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, errIAMActionNotAllowed), r.URL)
|
||||
return
|
||||
}
|
||||
|
||||
if err := globalIAMSys.DeleteUser(accessKey); err != nil {
|
||||
writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL)
|
||||
return
|
||||
@@ -518,6 +528,18 @@ func (a adminAPIHandlers) SetPolicyForUserOrGroup(w http.ResponseWriter, r *http
|
||||
return
|
||||
}
|
||||
|
||||
if !isGroup {
|
||||
ok, err := globalIAMSys.IsTempUser(entityName)
|
||||
if err != nil {
|
||||
writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL)
|
||||
return
|
||||
}
|
||||
if ok {
|
||||
writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, errIAMActionNotAllowed), r.URL)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if err := globalIAMSys.PolicyDBSet(entityName, policyName, isGroup); err != nil {
|
||||
writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL)
|
||||
return
|
||||
|
||||
+1
-2
@@ -188,7 +188,6 @@ func handleCommonEnvVars() {
|
||||
for _, addr := range addrs {
|
||||
domainIPs.Add(addr)
|
||||
}
|
||||
continue
|
||||
}
|
||||
domainIPs.Add(endpoint)
|
||||
}
|
||||
@@ -196,7 +195,7 @@ func handleCommonEnvVars() {
|
||||
} else {
|
||||
// Add found interfaces IP address to global domain IPS,
|
||||
// loopback addresses will be naturally dropped.
|
||||
updateDomainIPs(localIP4)
|
||||
updateDomainIPs(mustGetLocalIP4())
|
||||
}
|
||||
|
||||
// In place update is true by default if the MINIO_UPDATE is not set
|
||||
|
||||
@@ -251,7 +251,7 @@ func validateConfig(s config.Config) error {
|
||||
}
|
||||
}
|
||||
{
|
||||
kmsCfg, err := crypto.LookupConfig(s, globalCertsCADir.Get())
|
||||
kmsCfg, err := crypto.LookupConfig(s, globalCertsCADir.Get(), NewCustomHTTPTransport())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -355,7 +355,7 @@ func lookupConfigs(s config.Config) {
|
||||
}
|
||||
}
|
||||
|
||||
kmsCfg, err := crypto.LookupConfig(s, globalCertsCADir.Get())
|
||||
kmsCfg, err := crypto.LookupConfig(s, globalCertsCADir.Get(), NewCustomHTTPTransport())
|
||||
if err != nil {
|
||||
logger.LogIf(ctx, fmt.Errorf("Unable to setup KMS config: %w", err))
|
||||
}
|
||||
|
||||
@@ -154,6 +154,8 @@ func (c *CoreDNS) list(key string) ([]SrvRecord, error) {
|
||||
|
||||
// Put - Adds DNS entries into etcd endpoint in CoreDNS etcd message format.
|
||||
func (c *CoreDNS) Put(bucket string) error {
|
||||
c.Delete(bucket) // delete any existing entries.
|
||||
|
||||
for ip := range c.domainIPs {
|
||||
bucketMsg, err := newCoreDNSMsg(ip, c.domainPort, defaultTTL)
|
||||
if err != nil {
|
||||
|
||||
@@ -17,6 +17,7 @@ package crypto
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"reflect"
|
||||
"strconv"
|
||||
|
||||
@@ -259,7 +260,7 @@ func lookupAutoEncryption() (bool, error) {
|
||||
|
||||
// LookupConfig lookup vault or kes config, returns KMSConfig
|
||||
// to configure KMS object for object encryption
|
||||
func LookupConfig(c config.Config, defaultRootCAsDir string) (KMSConfig, error) {
|
||||
func LookupConfig(c config.Config, defaultRootCAsDir string, transport *http.Transport) (KMSConfig, error) {
|
||||
vcfg, err := LookupVaultConfig(c[config.KmsVaultSubSys][config.Default])
|
||||
if err != nil {
|
||||
return KMSConfig{}, err
|
||||
@@ -268,6 +269,7 @@ func LookupConfig(c config.Config, defaultRootCAsDir string) (KMSConfig, error)
|
||||
if err != nil {
|
||||
return KMSConfig{}, err
|
||||
}
|
||||
kesCfg.Transport = transport
|
||||
if kesCfg.Enabled && kesCfg.CAPath == "" {
|
||||
kesCfg.CAPath = defaultRootCAsDir
|
||||
}
|
||||
|
||||
+124
-7
@@ -18,13 +18,16 @@ import (
|
||||
"bytes"
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/minio/kes"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// KesConfig contains the configuration required
|
||||
@@ -63,6 +66,10 @@ type KesConfig struct {
|
||||
|
||||
// The default key ID returned by KMS.KeyID().
|
||||
DefaultKeyID string
|
||||
|
||||
// The HTTP transport configuration for
|
||||
// the KES client.
|
||||
Transport *http.Transport
|
||||
}
|
||||
|
||||
// Verify verifies if the kes configuration is correct
|
||||
@@ -81,7 +88,7 @@ func (k KesConfig) Verify() (err error) {
|
||||
}
|
||||
|
||||
type kesService struct {
|
||||
client *kes.Client
|
||||
client *kesClient
|
||||
|
||||
endpoint string
|
||||
defaultKeyID string
|
||||
@@ -102,11 +109,17 @@ func NewKes(cfg KesConfig) (KMS, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cfg.Transport.TLSClientConfig = &tls.Config{
|
||||
Certificates: []tls.Certificate{cert},
|
||||
RootCAs: certPool,
|
||||
}
|
||||
return &kesService{
|
||||
client: kes.NewClient(cfg.Endpoint, &tls.Config{
|
||||
Certificates: []tls.Certificate{cert},
|
||||
RootCAs: certPool,
|
||||
}),
|
||||
client: &kesClient{
|
||||
addr: cfg.Endpoint,
|
||||
httpClient: http.Client{
|
||||
Transport: cfg.Transport,
|
||||
},
|
||||
},
|
||||
endpoint: cfg.Endpoint,
|
||||
defaultKeyID: cfg.DefaultKeyID,
|
||||
}, nil
|
||||
@@ -187,6 +200,110 @@ func (kes *kesService) UpdateKey(keyID string, sealedKey []byte, ctx Context) ([
|
||||
return sealedKey, nil
|
||||
}
|
||||
|
||||
// kesClient implements the bare minimum functionality needed for
|
||||
// MinIO to talk to a KES server. In particular, it implements
|
||||
// GenerateDataKey (API: /v1/key/generate/) and
|
||||
// DecryptDataKey (API: /v1/key/decrypt/).
|
||||
type kesClient struct {
|
||||
addr string
|
||||
httpClient http.Client
|
||||
}
|
||||
|
||||
// GenerateDataKey requests a new data key from the KES server.
|
||||
// On success, the KES server will respond with the plaintext key
|
||||
// and the ciphertext key as the plaintext key encrypted with
|
||||
// the key specified by name.
|
||||
//
|
||||
// The optional context is crytpo. bound to the generated data key
|
||||
// such that you have to provide the same context when decrypting
|
||||
// the data key.
|
||||
func (c *kesClient) GenerateDataKey(name string, context []byte) ([]byte, []byte, error) {
|
||||
type Request struct {
|
||||
Context []byte `json:"context"`
|
||||
}
|
||||
body, err := json.Marshal(Request{
|
||||
Context: context,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
url := fmt.Sprintf("%s/v1/key/generate/%s", c.addr, url.PathEscape(name))
|
||||
resp, err := c.httpClient.Post(url, "application/json", bytes.NewReader(body))
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return nil, nil, c.parseErrorResponse(resp)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
type Response struct {
|
||||
Plaintext []byte `json:"plaintext"`
|
||||
Ciphertext []byte `json:"ciphertext"`
|
||||
}
|
||||
const limit = 1 << 20 // A plaintext/ciphertext key pair will never be larger than 1 MB
|
||||
var response Response
|
||||
if err = json.NewDecoder(io.LimitReader(resp.Body, limit)).Decode(&response); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
return response.Plaintext, response.Ciphertext, nil
|
||||
}
|
||||
|
||||
// GenerateDataKey decrypts an encrypted data key with the key
|
||||
// specified by name by talking to the KES server.
|
||||
// On success, the KES server will respond with the plaintext key.
|
||||
//
|
||||
// The optional context must match the value you provided when
|
||||
// generating the data key.
|
||||
func (c *kesClient) DecryptDataKey(name string, ciphertext, context []byte) ([]byte, error) {
|
||||
type Request struct {
|
||||
Ciphertext []byte `json:"ciphertext"`
|
||||
Context []byte `json:"context"`
|
||||
}
|
||||
body, err := json.Marshal(Request{
|
||||
Ciphertext: ciphertext,
|
||||
Context: context,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
url := fmt.Sprintf("%s/v1/key/decrypt/%s", c.addr, url.PathEscape(name))
|
||||
resp, err := c.httpClient.Post(url, "application/json", bytes.NewReader(body))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return nil, c.parseErrorResponse(resp)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
type Response struct {
|
||||
Plaintext []byte `json:"plaintext"`
|
||||
}
|
||||
const limit = 32 * 1024 // A data key will never be larger than 32 KB
|
||||
var response Response
|
||||
if err = json.NewDecoder(io.LimitReader(resp.Body, limit)).Decode(&response); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return response.Plaintext, nil
|
||||
}
|
||||
|
||||
func (c *kesClient) parseErrorResponse(resp *http.Response) error {
|
||||
if resp.Body == nil {
|
||||
return nil
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
const limit = 32 * 1024 // A (valid) error response will not be greater than 32 KB
|
||||
var errMsg strings.Builder
|
||||
if _, err := io.Copy(&errMsg, io.LimitReader(resp.Body, limit)); err != nil {
|
||||
return err
|
||||
}
|
||||
return fmt.Errorf("%s: %s", http.StatusText(resp.StatusCode), errMsg.String())
|
||||
}
|
||||
|
||||
// loadCACertificates returns a new CertPool
|
||||
// that contains all system root CA certificates
|
||||
// and any PEM-encoded certificate(s) found at
|
||||
|
||||
@@ -220,10 +220,10 @@ func (c *diskCache) purge() {
|
||||
}
|
||||
ctx := context.Background()
|
||||
for {
|
||||
olderThan := c.expiry
|
||||
olderThan := c.expiry * 24
|
||||
for !c.diskUsageLow() {
|
||||
// delete unaccessed objects older than expiry duration
|
||||
expiry := UTCNow().AddDate(0, 0, -1*olderThan)
|
||||
expiry := UTCNow().Add(time.Hour * time.Duration(-1*olderThan))
|
||||
olderThan /= 2
|
||||
if olderThan < 1 {
|
||||
break
|
||||
|
||||
@@ -270,7 +270,7 @@ func createServerEndpoints(serverAddr string, args ...string) (EndpointZones, in
|
||||
if err != nil {
|
||||
return nil, -1, -1, err
|
||||
}
|
||||
endpointList, newSetupType, err := CreateEndpoints(serverAddr, setArgs...)
|
||||
endpointList, newSetupType, err := CreateEndpoints(serverAddr, false, setArgs...)
|
||||
if err != nil {
|
||||
return nil, -1, -1, err
|
||||
}
|
||||
@@ -283,6 +283,8 @@ func createServerEndpoints(serverAddr string, args ...string) (EndpointZones, in
|
||||
return endpointZones, len(setArgs[0]), setupType, nil
|
||||
}
|
||||
|
||||
var foundPrevLocal bool
|
||||
|
||||
// Verify the args setup-type appropriately.
|
||||
{
|
||||
setArgs, err := GetAllSets(args...)
|
||||
@@ -290,10 +292,13 @@ func createServerEndpoints(serverAddr string, args ...string) (EndpointZones, in
|
||||
return nil, -1, -1, err
|
||||
}
|
||||
|
||||
_, setupType, err = CreateEndpoints(serverAddr, setArgs...)
|
||||
var endpoints Endpoints
|
||||
endpoints, setupType, err = CreateEndpoints(serverAddr, foundPrevLocal, setArgs...)
|
||||
if err != nil {
|
||||
return nil, -1, -1, err
|
||||
}
|
||||
|
||||
foundPrevLocal = endpoints.atleastOneEndpointLocal()
|
||||
}
|
||||
|
||||
for _, arg := range args {
|
||||
@@ -301,7 +306,7 @@ func createServerEndpoints(serverAddr string, args ...string) (EndpointZones, in
|
||||
if err != nil {
|
||||
return nil, -1, -1, err
|
||||
}
|
||||
endpointList, _, err := CreateEndpoints(serverAddr, setArgs...)
|
||||
endpointList, _, err := CreateEndpoints(serverAddr, foundPrevLocal, setArgs...)
|
||||
if err != nil {
|
||||
return nil, -1, -1, err
|
||||
}
|
||||
|
||||
+52
-42
@@ -230,6 +230,25 @@ func (endpoints Endpoints) GetString(i int) string {
|
||||
return endpoints[i].String()
|
||||
}
|
||||
|
||||
func (endpoints Endpoints) doAnyHostsResolveToLocalhost() bool {
|
||||
for _, endpoint := range endpoints {
|
||||
hostIPs, err := getHostIP(endpoint.Hostname())
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
var loopback int
|
||||
for _, hostIP := range hostIPs.ToSlice() {
|
||||
if net.ParseIP(hostIP).IsLoopback() {
|
||||
loopback++
|
||||
}
|
||||
}
|
||||
if loopback == len(hostIPs) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (endpoints Endpoints) atleastOneEndpointLocal() bool {
|
||||
for _, endpoint := range endpoints {
|
||||
if endpoint.IsLocal {
|
||||
@@ -239,36 +258,10 @@ func (endpoints Endpoints) atleastOneEndpointLocal() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (endpoints Endpoints) doAllHostsResolveToLocalhost() bool {
|
||||
var endpointHosts = map[string]set.StringSet{}
|
||||
for _, endpoint := range endpoints {
|
||||
hostIPs, err := getHostIP(endpoint.Hostname())
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
endpointHosts[endpoint.Hostname()] = hostIPs
|
||||
}
|
||||
sameHosts := make(map[string]int)
|
||||
for hostName, endpointIPs := range endpointHosts {
|
||||
for _, endpointIP := range endpointIPs.ToSlice() {
|
||||
if net.ParseIP(endpointIP).IsLoopback() {
|
||||
sameHosts[hostName]++
|
||||
}
|
||||
}
|
||||
}
|
||||
ok := true
|
||||
for _, localCount := range sameHosts {
|
||||
ok = ok && localCount > 0
|
||||
}
|
||||
if len(sameHosts) == 0 {
|
||||
return false
|
||||
}
|
||||
return ok
|
||||
}
|
||||
|
||||
// UpdateIsLocal - resolves the host and discovers the local host.
|
||||
func (endpoints Endpoints) UpdateIsLocal() error {
|
||||
func (endpoints Endpoints) UpdateIsLocal(foundPrevLocal bool) error {
|
||||
orchestrated := IsDocker() || IsKubernetes()
|
||||
k8sReplicaSet := IsKubernetesReplicaSet()
|
||||
|
||||
var epsResolved int
|
||||
var foundLocal bool
|
||||
@@ -301,8 +294,8 @@ func (endpoints Endpoints) UpdateIsLocal() error {
|
||||
endpoints[i].Hostname(),
|
||||
)
|
||||
|
||||
if orchestrated && endpoints.doAllHostsResolveToLocalhost() {
|
||||
err := errors.New("hosts resolve to same IP, DNS not updated on k8s")
|
||||
if k8sReplicaSet && endpoints.doAnyHostsResolveToLocalhost() {
|
||||
err := errors.New("host found resolves to 127.*, DNS incorrectly configured retrying")
|
||||
// time elapsed
|
||||
timeElapsed := time.Since(startTime)
|
||||
// log error only if more than 1s elapsed
|
||||
@@ -346,7 +339,18 @@ func (endpoints Endpoints) UpdateIsLocal() error {
|
||||
} else {
|
||||
resolvedList[i] = true
|
||||
endpoints[i].IsLocal = isLocal
|
||||
if orchestrated && !endpoints.atleastOneEndpointLocal() {
|
||||
if k8sReplicaSet && !endpoints.atleastOneEndpointLocal() && !foundPrevLocal {
|
||||
// In replicated set in k8s deployment, IPs might
|
||||
// get resolved for older IPs, add this code
|
||||
// to ensure that we wait for this server to
|
||||
// participate atleast one disk and be local.
|
||||
//
|
||||
// In special cases for replica set with expanded
|
||||
// zone setups we need to make sure to provide
|
||||
// value of foundPrevLocal from zone1 if we already
|
||||
// found a local setup. Only if we haven't found
|
||||
// previous local we continue to wait to look for
|
||||
// atleast one local.
|
||||
resolvedList[i] = false
|
||||
continue
|
||||
}
|
||||
@@ -460,7 +464,7 @@ func checkCrossDeviceMounts(endpoints Endpoints) (err error) {
|
||||
}
|
||||
|
||||
// CreateEndpoints - validates and creates new endpoints for given args.
|
||||
func CreateEndpoints(serverAddr string, args ...[]string) (Endpoints, SetupType, error) {
|
||||
func CreateEndpoints(serverAddr string, foundLocal bool, args ...[]string) (Endpoints, SetupType, error) {
|
||||
var endpoints Endpoints
|
||||
var setupType SetupType
|
||||
var err error
|
||||
@@ -526,7 +530,7 @@ func CreateEndpoints(serverAddr string, args ...[]string) (Endpoints, SetupType,
|
||||
return endpoints, setupType, nil
|
||||
}
|
||||
|
||||
if err = endpoints.UpdateIsLocal(); err != nil {
|
||||
if err = endpoints.UpdateIsLocal(foundLocal); err != nil {
|
||||
return endpoints, setupType, config.ErrInvalidErasureEndpoints(nil).Msg(err.Error())
|
||||
}
|
||||
|
||||
@@ -694,22 +698,28 @@ func updateDomainIPs(endPoints set.StringSet) {
|
||||
continue
|
||||
}
|
||||
}
|
||||
IPs, err := getHostIP(host)
|
||||
if err != nil {
|
||||
continue
|
||||
|
||||
if net.ParseIP(host) == nil {
|
||||
IPs, err := getHostIP(host)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
IPsWithPort := IPs.ApplyFunc(func(ip string) string {
|
||||
return net.JoinHostPort(ip, port)
|
||||
})
|
||||
|
||||
ipList = ipList.Union(IPsWithPort)
|
||||
}
|
||||
|
||||
IPsWithPort := IPs.ApplyFunc(func(ip string) string {
|
||||
return net.JoinHostPort(ip, port)
|
||||
})
|
||||
|
||||
ipList = ipList.Union(IPsWithPort)
|
||||
ipList.Add(net.JoinHostPort(host, port))
|
||||
}
|
||||
|
||||
globalDomainIPs = ipList.FuncMatch(func(ip string, matchString string) bool {
|
||||
host, _, err := net.SplitHostPort(ip)
|
||||
if err != nil {
|
||||
host = ip
|
||||
}
|
||||
return !net.ParseIP(host).IsLoopback()
|
||||
return !net.ParseIP(host).IsLoopback() && host != "localhost"
|
||||
}, "")
|
||||
}
|
||||
|
||||
@@ -341,7 +341,7 @@ func TestCreateEndpoints(t *testing.T) {
|
||||
for _, testCase := range testCases {
|
||||
testCase := testCase
|
||||
t.Run("", func(t *testing.T) {
|
||||
endpoints, setupType, err := CreateEndpoints(testCase.serverAddr, testCase.args...)
|
||||
endpoints, setupType, err := CreateEndpoints(testCase.serverAddr, false, testCase.args...)
|
||||
if err == nil && testCase.expectedErr != nil {
|
||||
t.Errorf("error: expected = %v, got = <nil>", testCase.expectedErr)
|
||||
}
|
||||
@@ -398,7 +398,7 @@ func TestGetLocalPeer(t *testing.T) {
|
||||
for i, testCase := range testCases {
|
||||
zendpoints := mustGetZoneEndpoints(testCase.endpointArgs...)
|
||||
if !zendpoints[0].Endpoints[0].IsLocal {
|
||||
if err := zendpoints[0].Endpoints.UpdateIsLocal(); err != nil {
|
||||
if err := zendpoints[0].Endpoints.UpdateIsLocal(false); err != nil {
|
||||
t.Fatalf("error: expected = <nil>, got = %v", err)
|
||||
}
|
||||
}
|
||||
@@ -430,7 +430,7 @@ func TestGetRemotePeers(t *testing.T) {
|
||||
for _, testCase := range testCases {
|
||||
zendpoints := mustGetZoneEndpoints(testCase.endpointArgs...)
|
||||
if !zendpoints[0].Endpoints[0].IsLocal {
|
||||
if err := zendpoints[0].Endpoints.UpdateIsLocal(); err != nil {
|
||||
if err := zendpoints[0].Endpoints.UpdateIsLocal(false); err != nil {
|
||||
t.Fatalf("error: expected = <nil>, got = %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -637,7 +637,7 @@ func (f bucketForwardingHandler) ServeHTTP(w http.ResponseWriter, r *http.Reques
|
||||
if t := r.URL.Query().Get("token"); t != "" {
|
||||
bucket, _ = urlPath2BucketObjectName(strings.TrimPrefix(r.URL.Path, minioReservedBucketPath+"/download"))
|
||||
} else if getRequestAuthType(r) != authTypeJWT && !strings.HasPrefix(r.URL.Path, minioReservedBucketPath) {
|
||||
bucket, _ = urlPath2BucketObjectName(r.URL.Path)
|
||||
bucket, _ = request2BucketObjectName(r)
|
||||
}
|
||||
}
|
||||
if bucket == "" {
|
||||
|
||||
+50
-10
@@ -600,20 +600,40 @@ func (sys *IAMSys) ListUsers() (map[string]madmin.UserInfo, error) {
|
||||
}
|
||||
|
||||
for k, v := range sys.iamUsersMap {
|
||||
users[k] = madmin.UserInfo{
|
||||
PolicyName: sys.iamUserPolicyMap[k].Policy,
|
||||
Status: func() madmin.AccountStatus {
|
||||
if v.IsValid() {
|
||||
return madmin.AccountEnabled
|
||||
}
|
||||
return madmin.AccountDisabled
|
||||
}(),
|
||||
if !v.IsTemp() {
|
||||
users[k] = madmin.UserInfo{
|
||||
PolicyName: sys.iamUserPolicyMap[k].Policy,
|
||||
Status: func() madmin.AccountStatus {
|
||||
if v.IsValid() {
|
||||
return madmin.AccountEnabled
|
||||
}
|
||||
return madmin.AccountDisabled
|
||||
}(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return users, nil
|
||||
}
|
||||
|
||||
// IsTempUser - returns if given key is a temporary user.
|
||||
func (sys *IAMSys) IsTempUser(name string) (bool, error) {
|
||||
objectAPI := newObjectLayerWithoutSafeModeFn()
|
||||
if objectAPI == nil {
|
||||
return false, errServerNotInitialized
|
||||
}
|
||||
|
||||
sys.RLock()
|
||||
defer sys.RUnlock()
|
||||
|
||||
creds, found := sys.iamUsersMap[name]
|
||||
if !found {
|
||||
return false, errNoSuchUser
|
||||
}
|
||||
|
||||
return creds.IsTemp(), nil
|
||||
}
|
||||
|
||||
// GetUserInfo - get info on a user.
|
||||
func (sys *IAMSys) GetUserInfo(name string) (u madmin.UserInfo, err error) {
|
||||
objectAPI := newObjectLayerWithoutSafeModeFn()
|
||||
@@ -636,6 +656,10 @@ func (sys *IAMSys) GetUserInfo(name string) (u madmin.UserInfo, err error) {
|
||||
return u, errNoSuchUser
|
||||
}
|
||||
|
||||
if creds.IsTemp() {
|
||||
return u, errIAMActionNotAllowed
|
||||
}
|
||||
|
||||
u = madmin.UserInfo{
|
||||
PolicyName: sys.iamUserPolicyMap[name].Policy,
|
||||
Status: func() madmin.AccountStatus {
|
||||
@@ -672,6 +696,10 @@ func (sys *IAMSys) SetUserStatus(accessKey string, status madmin.AccountStatus)
|
||||
return errNoSuchUser
|
||||
}
|
||||
|
||||
if cred.IsTemp() {
|
||||
return errIAMActionNotAllowed
|
||||
}
|
||||
|
||||
uinfo := newUserIdentity(auth.Credentials{
|
||||
AccessKey: accessKey,
|
||||
SecretKey: cred.SecretKey,
|
||||
@@ -719,9 +747,15 @@ func (sys *IAMSys) SetUser(accessKey string, uinfo madmin.UserInfo) error {
|
||||
return errServerNotInitialized
|
||||
}
|
||||
|
||||
cr, ok := sys.iamUsersMap[accessKey]
|
||||
if cr.IsTemp() && ok {
|
||||
return errIAMActionNotAllowed
|
||||
}
|
||||
|
||||
if err := sys.store.saveUserIdentity(accessKey, false, u); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
sys.iamUsersMap[accessKey] = u.Credentials
|
||||
|
||||
// Set policy if specified.
|
||||
@@ -794,10 +828,13 @@ func (sys *IAMSys) AddUsersToGroup(group string, members []string) error {
|
||||
|
||||
// Validate that all members exist.
|
||||
for _, member := range members {
|
||||
_, ok := sys.iamUsersMap[member]
|
||||
cr, ok := sys.iamUsersMap[member]
|
||||
if !ok {
|
||||
return errNoSuchUser
|
||||
}
|
||||
if cr.IsTemp() {
|
||||
return errIAMActionNotAllowed
|
||||
}
|
||||
}
|
||||
|
||||
gi, ok := sys.iamGroupsMap[group]
|
||||
@@ -856,10 +893,13 @@ func (sys *IAMSys) RemoveUsersFromGroup(group string, members []string) error {
|
||||
|
||||
// Validate that all members exist.
|
||||
for _, member := range members {
|
||||
_, ok := sys.iamUsersMap[member]
|
||||
cr, ok := sys.iamUsersMap[member]
|
||||
if !ok {
|
||||
return errNoSuchUser
|
||||
}
|
||||
if cr.IsTemp() {
|
||||
return errIAMActionNotAllowed
|
||||
}
|
||||
}
|
||||
|
||||
gi, ok := sys.iamGroupsMap[group]
|
||||
|
||||
+4
-4
@@ -162,8 +162,8 @@ func sortIPs(ipList []string) []string {
|
||||
func getAPIEndpoints() (apiEndpoints []string) {
|
||||
var ipList []string
|
||||
if globalMinioHost == "" {
|
||||
ipList = sortIPs(localIP4.ToSlice())
|
||||
ipList = append(ipList, localIP6.ToSlice()...)
|
||||
ipList = sortIPs(mustGetLocalIP4().ToSlice())
|
||||
ipList = append(ipList, mustGetLocalIP6().ToSlice()...)
|
||||
} else {
|
||||
ipList = []string{globalMinioHost}
|
||||
}
|
||||
@@ -278,8 +278,8 @@ func isLocalHost(host string, port string, localPort string) (bool, error) {
|
||||
}
|
||||
|
||||
// If intersection of two IP sets is not empty, then the host is localhost.
|
||||
isLocalv4 := !localIP4.Intersection(hostIPs).IsEmpty()
|
||||
isLocalv6 := !localIP6.Intersection(hostIPs).IsEmpty()
|
||||
isLocalv4 := !mustGetLocalIP4().Intersection(hostIPs).IsEmpty()
|
||||
isLocalv6 := !mustGetLocalIP6().Intersection(hostIPs).IsEmpty()
|
||||
if port != "" {
|
||||
return (isLocalv4 || isLocalv6) && (port == localPort), nil
|
||||
}
|
||||
|
||||
@@ -798,6 +798,10 @@ func (sys *NotificationSys) RemoveRulesMap(bucketName string, rulesMap event.Rul
|
||||
|
||||
// ConfiguredTargetIDs - returns list of configured target id's
|
||||
func (sys *NotificationSys) ConfiguredTargetIDs() []event.TargetID {
|
||||
if sys == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
sys.RLock()
|
||||
defer sys.RUnlock()
|
||||
|
||||
|
||||
@@ -154,6 +154,11 @@ func IsDCOS() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// IsKubernetesReplicaSet returns true if minio is running in kubernetes replica set.
|
||||
func IsKubernetesReplicaSet() bool {
|
||||
return IsKubernetes() && (env.Get("KUBERNETES_REPLICA_SET", "") != "")
|
||||
}
|
||||
|
||||
// IsKubernetes returns true if minio is running in kubernetes.
|
||||
func IsKubernetes() bool {
|
||||
if env.Get("SIMPLE_CI", "") == "" {
|
||||
|
||||
@@ -81,6 +81,11 @@ func TestReleaseTagToNFromTimeConversion(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestDownloadURL(t *testing.T) {
|
||||
sci := os.Getenv("SIMPLE_CI")
|
||||
|
||||
os.Setenv("SIMPLE_CI", "")
|
||||
defer os.Setenv("SIMPLE_CI", sci)
|
||||
|
||||
minioVersion1 := releaseTimeToReleaseTag(UTCNow())
|
||||
durl := getDownloadURL(minioVersion1)
|
||||
if IsDocker() {
|
||||
@@ -143,6 +148,9 @@ func TestUserAgent(t *testing.T) {
|
||||
}
|
||||
|
||||
for i, testCase := range testCases {
|
||||
sci := os.Getenv("SIMPLE_CI")
|
||||
os.Setenv("SIMPLE_CI", "")
|
||||
|
||||
os.Setenv(testCase.envName, testCase.envValue)
|
||||
if testCase.envName == "MESOS_CONTAINER_NAME" {
|
||||
os.Setenv("MARATHON_APP_LABEL_DCOS_PACKAGE_VERSION", "mesos-1111")
|
||||
@@ -155,6 +163,7 @@ func TestUserAgent(t *testing.T) {
|
||||
if str != expectedStr {
|
||||
t.Errorf("Test %d: expected: %s, got: %s", i+1, expectedStr, str)
|
||||
}
|
||||
os.Setenv("SIMPLE_CI", sci)
|
||||
os.Unsetenv("MARATHON_APP_LABEL_DCOS_PACKAGE_VERSION")
|
||||
os.Unsetenv(testCase.envName)
|
||||
}
|
||||
@@ -162,6 +171,10 @@ func TestUserAgent(t *testing.T) {
|
||||
|
||||
// Tests if the environment we are running is in DCOS.
|
||||
func TestIsDCOS(t *testing.T) {
|
||||
sci := os.Getenv("SIMPLE_CI")
|
||||
os.Setenv("SIMPLE_CI", "")
|
||||
defer os.Setenv("SIMPLE_CI", sci)
|
||||
|
||||
os.Setenv("MESOS_CONTAINER_NAME", "mesos-1111")
|
||||
dcos := IsDCOS()
|
||||
if !dcos {
|
||||
@@ -177,6 +190,10 @@ func TestIsDCOS(t *testing.T) {
|
||||
|
||||
// Tests if the environment we are running is in kubernetes.
|
||||
func TestIsKubernetes(t *testing.T) {
|
||||
sci := os.Getenv("SIMPLE_CI")
|
||||
os.Setenv("SIMPLE_CI", "")
|
||||
defer os.Setenv("SIMPLE_CI", sci)
|
||||
|
||||
os.Setenv("KUBERNETES_SERVICE_HOST", "10.11.148.5")
|
||||
kubernetes := IsKubernetes()
|
||||
if !kubernetes {
|
||||
|
||||
@@ -5,8 +5,8 @@ Events occurring on objects in a bucket can be monitored using bucket event noti
|
||||
| Supported Event Types | | |
|
||||
| :---------------------- | ------------------------------------------ | ------------------------ |
|
||||
| `s3:ObjectCreated:Put` | `s3:ObjectCreated:CompleteMultipartUpload` | `s3:ObjectAccessed:Head` |
|
||||
| `s3:ObjectCreated:Post` | `s3:ObjectRemoved:Delete` |
|
||||
| `s3:ObjectCreated:Copy` | `s3:ObjectAccessed:Get` |
|
||||
| `s3:ObjectCreated:Post` | `s3:ObjectRemoved:Delete` | |
|
||||
| `s3:ObjectCreated:Copy` | `s3:ObjectAccessed:Get` | |
|
||||
|
||||
Use client tools like `mc` to set and listen for event notifications using the [`event` sub-command](https://docs.min.io/docs/minio-client-complete-guide#events). MinIO SDK's [`BucketNotification` APIs](https://docs.min.io/docs/golang-client-api-reference#SetBucketNotification) can also be used. The notification message MinIO sends to publish an event is a JSON message with the following [structure](https://docs.aws.amazon.com/AmazonS3/latest/dev/notification-content-structure.html).
|
||||
|
||||
@@ -24,6 +24,20 @@ Bucket events can be published to the following targets:
|
||||
- Install and configure MinIO Server from [here](https://docs.min.io/docs/minio-quickstart-guide).
|
||||
- Install and configure MinIO Client from [here](https://docs.min.io/docs/minio-client-quickstart-guide).
|
||||
|
||||
```
|
||||
$ mc admin config get myminio | grep notify
|
||||
notify_webhook publish bucket notifications to webhook endpoints
|
||||
notify_amqp publish bucket notifications to AMQP endpoints
|
||||
notify_kafka publish bucket notifications to Kafka endpoints
|
||||
notify_mqtt publish bucket notifications to MQTT endpoints
|
||||
notify_nats publish bucket notifications to NATS endpoints
|
||||
notify_nsq publish bucket notifications to NSQ endpoints
|
||||
notify_mysql publish bucket notifications to MySQL databases
|
||||
notify_postgres publish bucket notifications to Postgres databases
|
||||
notify_elasticsearch publish bucket notifications to Elasticsearch endpoints
|
||||
notify_redis publish bucket notifications to Redis datastores
|
||||
```
|
||||
|
||||
<a name="AMQP"></a>
|
||||
|
||||
## Publish MinIO events via AMQP
|
||||
@@ -403,13 +417,12 @@ The steps below show how to use this notification target in `namespace` and `acc
|
||||
The MinIO server configuration file is stored on the backend in json format.The Redis configuration is located in the `redis` key under the `notify` top-level key. Create a configuration key-value pair here for your Redis instance. The key is a name for your Redis endpoint, and the value is a collection of key-value parameters described in the table below.
|
||||
|
||||
| Parameter | Description |
|
||||
| :--------- | :------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
||||
| `state` | (Required) Is this server endpoint configuration active/enabled? |
|
||||
| `format` | (Required) Either `namespace` or `access`. |
|
||||
| `address` | (Required) The Redis server's address. For example: `localhost:6379`. |
|
||||
| `password` | (Optional) The Redis server's password. |
|
||||
| :--------- | :------------- |
|
||||
| `state` | (Required) Is this server endpoint configuration active/enabled? |
|
||||
| `format` | (Required) Either `namespace` or `access` |
|
||||
| `address` | (Required) The Redis server's address. For example: `localhost:6379` |
|
||||
| `password` | (Optional) The Redis server's password |
|
||||
| `key` | (Required) The name of the redis key under which events are stored. A hash is used in case of `namespace` format and a list in case of `access` format. |
|
||||
| | |
|
||||
|
||||
MinIO supports persistent event store. The persistent store will backup events when the Redis broker goes offline and replays it when the broker comes back online. The event store can be configured by setting the directory path in `queue_dir` field and the maximum limit of events in the queue_dir in `queue_limit` field. For eg, the `queue_dir` can be `/home/events` and `queue_limit` can be `1000`. By default, the `queue_limit` is set to 10000.
|
||||
|
||||
@@ -754,14 +767,16 @@ MinIO requires MySQL version 5.7.8 or above. MinIO uses the [JSON](https://dev.m
|
||||
|
||||
The MySQL configuration is located in the `notify_mysql` key. Create a configuration key-value pair here for your MySQL instance. The key is a name for your MySQL endpoint, and the value is a collection of key-value parameters described in the table below.
|
||||
|
||||
| Parameter | Description | | :---------- | :-------------- | | `state` | (Required) Is this server endpoint configuration active/enabled? |
|
||||
| `format` | (Required) Either `namespace` or `access`. | | `dsn_string` | (Optional) [Data-Source-Name connection string](https://github.com/go-sql-driver/mysql#dsn-data-source-name) for the MySQL server. |
|
||||
| Parameter | Description |
|
||||
| :---------- | :------------- |
|
||||
| `format` | (Required) Either `namespace` or `access`. |
|
||||
| `dsn_string` | (Optional) [Data-Source-Name connection string](https://github.com/go-sql-driver/mysql#dsn-data-source-name) for the MySQL server. |
|
||||
| `table` | (Required) Table name in which events will be stored/updated. If the table does not exist, the MinIO server creates it at start-up. |
|
||||
| `host` | Host name of the MySQL server (used only if `dsnString` is empty). |
|
||||
| `port` | Port on which to connect to the MySQL server (used only if `dsn_string` is empty). |
|
||||
| `user` | Database user-name (used only if `dsnString` is empty). |
|
||||
| `password` | Database password (used only if `dsnString` is empty). |
|
||||
| `database` | Database name (used only if `dsnString` is empty). |
|
||||
| `host` | Host name of the MySQL server (used only if `dsnString` is empty). |
|
||||
| `port` | Port on which to connect to the MySQL server (used only if `dsn_string` is empty). |
|
||||
| `user` | Database user-name (used only if `dsnString` is empty). |
|
||||
| `password` | Database password (used only if `dsnString` is empty). |
|
||||
| `database` | Database name (used only if `dsnString` is empty). |
|
||||
|
||||
`dns_string` is optional, if not specified, the connection information specified by the `host`, `port`, `user`, `password` and `database` parameters are used.
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
# MinIO Multi-user Quickstart Guide [](https://slack.min.io)
|
||||
MinIO supports multiple long term users in addition to default user created during server startup. New users can be added after server starts up, and server can be configured to deny or allow access to buckets and resources to each of these users. This document explains how to add/remove users and modify their access rights.
|
||||
|
||||
|
||||
## Get started
|
||||
In this document we will explain in detail on how to configure multiple users.
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ version: '3.7'
|
||||
# 9001 through 9004.
|
||||
services:
|
||||
minio1:
|
||||
image: minio/minio:RELEASE.2019-10-12T01-39-57Z
|
||||
image: minio/minio:RELEASE.2019-12-17T23-16-33Z
|
||||
volumes:
|
||||
- data1-1:/data1
|
||||
- data1-2:/data2
|
||||
@@ -22,7 +22,7 @@ services:
|
||||
retries: 3
|
||||
|
||||
minio2:
|
||||
image: minio/minio:RELEASE.2019-10-12T01-39-57Z
|
||||
image: minio/minio:RELEASE.2019-12-17T23-16-33Z
|
||||
volumes:
|
||||
- data2-1:/data1
|
||||
- data2-2:/data2
|
||||
@@ -39,7 +39,7 @@ services:
|
||||
retries: 3
|
||||
|
||||
minio3:
|
||||
image: minio/minio:RELEASE.2019-10-12T01-39-57Z
|
||||
image: minio/minio:RELEASE.2019-12-17T23-16-33Z
|
||||
volumes:
|
||||
- data3-1:/data1
|
||||
- data3-2:/data2
|
||||
@@ -56,7 +56,7 @@ services:
|
||||
retries: 3
|
||||
|
||||
minio4:
|
||||
image: minio/minio:RELEASE.2019-10-12T01-39-57Z
|
||||
image: minio/minio:RELEASE.2019-12-17T23-16-33Z
|
||||
volumes:
|
||||
- data4-1:/data1
|
||||
- data4-2:/data2
|
||||
|
||||
@@ -2,7 +2,7 @@ version: '3.7'
|
||||
|
||||
services:
|
||||
minio1:
|
||||
image: minio/minio:RELEASE.2019-10-12T01-39-57Z
|
||||
image: minio/minio:RELEASE.2019-12-17T23-16-33Z
|
||||
hostname: minio1
|
||||
volumes:
|
||||
- minio1-data:/export
|
||||
@@ -29,7 +29,7 @@ services:
|
||||
retries: 3
|
||||
|
||||
minio2:
|
||||
image: minio/minio:RELEASE.2019-10-12T01-39-57Z
|
||||
image: minio/minio:RELEASE.2019-12-17T23-16-33Z
|
||||
hostname: minio2
|
||||
volumes:
|
||||
- minio2-data:/export
|
||||
@@ -56,7 +56,7 @@ services:
|
||||
retries: 3
|
||||
|
||||
minio3:
|
||||
image: minio/minio:RELEASE.2019-10-12T01-39-57Z
|
||||
image: minio/minio:RELEASE.2019-12-17T23-16-33Z
|
||||
hostname: minio3
|
||||
volumes:
|
||||
- minio3-data:/export
|
||||
@@ -83,7 +83,7 @@ services:
|
||||
retries: 3
|
||||
|
||||
minio4:
|
||||
image: minio/minio:RELEASE.2019-10-12T01-39-57Z
|
||||
image: minio/minio:RELEASE.2019-12-17T23-16-33Z
|
||||
hostname: minio4
|
||||
volumes:
|
||||
- minio4-data:/export
|
||||
|
||||
@@ -2,7 +2,7 @@ version: '3.7'
|
||||
|
||||
services:
|
||||
minio1:
|
||||
image: minio/minio:RELEASE.2019-10-12T01-39-57Z
|
||||
image: minio/minio:RELEASE.2019-12-17T23-16-33Z
|
||||
hostname: minio1
|
||||
volumes:
|
||||
- minio1-data:/export
|
||||
@@ -33,7 +33,7 @@ services:
|
||||
retries: 3
|
||||
|
||||
minio2:
|
||||
image: minio/minio:RELEASE.2019-10-12T01-39-57Z
|
||||
image: minio/minio:RELEASE.2019-12-17T23-16-33Z
|
||||
hostname: minio2
|
||||
volumes:
|
||||
- minio2-data:/export
|
||||
@@ -64,7 +64,7 @@ services:
|
||||
retries: 3
|
||||
|
||||
minio3:
|
||||
image: minio/minio:RELEASE.2019-10-12T01-39-57Z
|
||||
image: minio/minio:RELEASE.2019-12-17T23-16-33Z
|
||||
hostname: minio3
|
||||
volumes:
|
||||
- minio3-data:/export
|
||||
@@ -95,7 +95,7 @@ services:
|
||||
retries: 3
|
||||
|
||||
minio4:
|
||||
image: minio/minio:RELEASE.2019-10-12T01-39-57Z
|
||||
image: minio/minio:RELEASE.2019-12-17T23-16-33Z
|
||||
hostname: minio4
|
||||
volumes:
|
||||
- minio4-data:/export
|
||||
|
||||
@@ -30,7 +30,7 @@ spec:
|
||||
value: "minio"
|
||||
- name: MINIO_SECRET_KEY
|
||||
value: "minio123"
|
||||
image: minio/minio:RELEASE.2019-10-12T01-39-57Z
|
||||
image: minio/minio:RELEASE.2019-12-17T23-16-33Z
|
||||
# Unfortunately you must manually define each server. Perhaps autodiscovery via DNS can be implemented in the future.
|
||||
args:
|
||||
- server
|
||||
|
||||
@@ -21,7 +21,7 @@ spec:
|
||||
value: "minio"
|
||||
- name: MINIO_SECRET_KEY
|
||||
value: "minio123"
|
||||
image: minio/minio:RELEASE.2019-10-12T01-39-57Z
|
||||
image: minio/minio:RELEASE.2019-12-17T23-16-33Z
|
||||
args:
|
||||
- server
|
||||
- http://minio-{0...3}.minio.default.svc.cluster.local/data
|
||||
|
||||
@@ -24,7 +24,7 @@ spec:
|
||||
containers:
|
||||
- name: minio
|
||||
# Pulls the default Minio image from Docker Hub
|
||||
image: minio/minio:RELEASE.2019-10-12T01-39-57Z
|
||||
image: minio/minio:RELEASE.2019-12-17T23-16-33Z
|
||||
args:
|
||||
- gateway
|
||||
- gcs
|
||||
|
||||
@@ -32,7 +32,7 @@ spec:
|
||||
- name: data
|
||||
mountPath: "/data"
|
||||
# Pulls the lastest Minio image from Docker Hub
|
||||
image: minio/minio:RELEASE.2019-10-12T01-39-57Z
|
||||
image: minio/minio:RELEASE.2019-12-17T23-16-33Z
|
||||
args:
|
||||
- server
|
||||
- /data
|
||||
|
||||
@@ -44,7 +44,6 @@ require (
|
||||
github.com/minio/gokrb5/v7 v7.2.5
|
||||
github.com/minio/hdfs/v3 v3.0.1
|
||||
github.com/minio/highwayhash v1.0.0
|
||||
github.com/minio/kes v0.4.0
|
||||
github.com/minio/lsync v1.0.1
|
||||
github.com/minio/mc v0.0.0-20191012041914-735aa139b19c
|
||||
github.com/minio/minio-go v0.0.0-20190327203652-5325257a208f
|
||||
|
||||
@@ -563,8 +563,6 @@ github.com/minio/hdfs/v3 v3.0.1/go.mod h1:6ALh9HsAwG9xAXdpdrZJcSY0vR6z3K+9XIz6Y9
|
||||
github.com/minio/highwayhash v0.0.0-20181220011308-93ed73d64169/go.mod h1:NL8wme5P5MoscwAkXfGroz3VgpCdhBw3KYOu5mEsvpU=
|
||||
github.com/minio/highwayhash v1.0.0 h1:iMSDhgUILCr0TNm8LWlSjF8N0ZIj2qbO8WHp6Q/J2BA=
|
||||
github.com/minio/highwayhash v1.0.0/go.mod h1:xQboMTeM9nY9v/LlAOxFctujiv5+Aq2hR5dxBpaMbdc=
|
||||
github.com/minio/kes v0.4.0 h1:N96zVEH/RnY4XfGf/gVz+j8DRyrYWDM2f24lF/K3LhA=
|
||||
github.com/minio/kes v0.4.0/go.mod h1:Y1hLsM+dhq0azrJ+7nxG1QaD8gliTUthFnvOk99FasQ=
|
||||
github.com/minio/lsync v0.0.0-20190207022115-a4e43e3d0887/go.mod h1:ni10+iSX7FO8N2rv41XM444V6w4rYO0dZo5KIkbn/YA=
|
||||
github.com/minio/lsync v1.0.1 h1:AVvILxA976xc27hstd1oR+X9PQG0sPSom1MNb1ImfUs=
|
||||
github.com/minio/lsync v1.0.1/go.mod h1:tCFzfo0dlvdGl70IT4IAK/5Wtgb0/BrTmo/jE8pArKA=
|
||||
@@ -702,8 +700,6 @@ github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144T
|
||||
github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ=
|
||||
github.com/pborman/getopt v0.0.0-20180729010549-6fdd0a2c7117/go.mod h1:85jBQOZwpVEaDAr341tbn15RS4fCAsIst0qp7i8ex1o=
|
||||
github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k=
|
||||
github.com/pelletier/go-toml v1.6.0 h1:aetoXYr0Tv7xRU/V4B4IZJ2QcbtMUFoNb3ORp7TzIK4=
|
||||
github.com/pelletier/go-toml v1.6.0/go.mod h1:5N711Q9dKgbdkxHL+MEfF31hpT7l0S0s/t2kKREewys=
|
||||
github.com/pierrec/lz4 v2.0.5+incompatible h1:2xWsjqPFWcplujydGg4WmhC/6fZqK42wMM8aXeqhl0I=
|
||||
github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
|
||||
github.com/pierrec/lz4 v2.2.6+incompatible h1:6aCX4/YZ9v8q69hTyiR7dNLnTA3fgtKHVVW5BCd5Znw=
|
||||
|
||||
@@ -117,6 +117,11 @@ func (cred Credentials) IsExpired() bool {
|
||||
return cred.Expiration.Before(time.Now().UTC())
|
||||
}
|
||||
|
||||
// IsTemp - returns whether credential is temporary or not.
|
||||
func (cred Credentials) IsTemp() bool {
|
||||
return cred.SessionToken != ""
|
||||
}
|
||||
|
||||
// IsValid - returns whether credential is valid or not.
|
||||
func (cred Credentials) IsValid() bool {
|
||||
// Verify credentials if its enabled or not set.
|
||||
|
||||
Reference in New Issue
Block a user