fips build tag uses relevant binary link for updates (#12014)

This code is necessary for `mc admin update` command
to work with fips compiled binaries, with fips tags
the releaseInfo will automatically point to fips
specific binaries.
This commit is contained in:
Harshavardhana 2021-04-08 09:51:11 -07:00 committed by GitHub
parent 835d2cb9a3
commit 641e564b65
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 74 additions and 40 deletions

View file

@ -64,8 +64,8 @@ const (
mgmtForceStop = "forceStop" mgmtForceStop = "forceStop"
) )
func updateServer(u *url.URL, sha256Sum []byte, lrTime time.Time, mode string) (us madmin.ServerUpdateStatus, err error) { func updateServer(u *url.URL, sha256Sum []byte, lrTime time.Time, releaseInfo string, mode string) (us madmin.ServerUpdateStatus, err error) {
if err = doUpdate(u, lrTime, sha256Sum, mode); err != nil { if err = doUpdate(u, lrTime, sha256Sum, releaseInfo, mode); err != nil {
return us, err return us, err
} }
@ -115,14 +115,13 @@ func (a adminAPIHandlers) ServerUpdateHandler(w http.ResponseWriter, r *http.Req
return return
} }
sha256Sum, lrTime, err := parseReleaseData(content) sha256Sum, lrTime, releaseInfo, err := parseReleaseData(content)
if err != nil { if err != nil {
writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL)
return return
} }
u.Path = path.Dir(u.Path) + SlashSeparator + "minio.RELEASE." + lrTime.Format(minioReleaseTagTimeLayout) u.Path = path.Dir(u.Path) + SlashSeparator + releaseInfo
crTime, err := GetCurrentReleaseTime() crTime, err := GetCurrentReleaseTime()
if err != nil { if err != nil {
writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL)
@ -146,7 +145,7 @@ func (a adminAPIHandlers) ServerUpdateHandler(w http.ResponseWriter, r *http.Req
return return
} }
for _, nerr := range globalNotificationSys.ServerUpdate(ctx, u, sha256Sum, lrTime) { for _, nerr := range globalNotificationSys.ServerUpdate(ctx, u, sha256Sum, lrTime, releaseInfo) {
if nerr.Err != nil { if nerr.Err != nil {
logger.GetReqInfo(ctx).SetTags("peerAddress", nerr.Host.String()) logger.GetReqInfo(ctx).SetTags("peerAddress", nerr.Host.String())
logger.LogIf(ctx, nerr.Err) logger.LogIf(ctx, nerr.Err)
@ -156,7 +155,7 @@ func (a adminAPIHandlers) ServerUpdateHandler(w http.ResponseWriter, r *http.Req
} }
} }
updateStatus, err := updateServer(u, sha256Sum, lrTime, mode) updateStatus, err := updateServer(u, sha256Sum, lrTime, releaseInfo, mode)
if err != nil { if err != nil {
err = fmt.Errorf("Server update failed, please do not restart the servers yet: failed with %w", err) err = fmt.Errorf("Server update failed, please do not restart the servers yet: failed with %w", err)
writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL)

View file

@ -400,7 +400,7 @@ func (sys *NotificationSys) DownloadProfilingData(ctx context.Context, writer io
} }
// ServerUpdate - updates remote peers. // ServerUpdate - updates remote peers.
func (sys *NotificationSys) ServerUpdate(ctx context.Context, u *url.URL, sha256Sum []byte, lrTime time.Time) []NotificationPeerErr { func (sys *NotificationSys) ServerUpdate(ctx context.Context, u *url.URL, sha256Sum []byte, lrTime time.Time, releaseInfo string) []NotificationPeerErr {
ng := WithNPeers(len(sys.peerClients)) ng := WithNPeers(len(sys.peerClients))
for idx, client := range sys.peerClients { for idx, client := range sys.peerClients {
if client == nil { if client == nil {
@ -408,7 +408,7 @@ func (sys *NotificationSys) ServerUpdate(ctx context.Context, u *url.URL, sha256
} }
client := client client := client
ng.Go(ctx, func() error { ng.Go(ctx, func() error {
return client.ServerUpdate(ctx, u, sha256Sum, lrTime) return client.ServerUpdate(ctx, u, sha256Sum, lrTime, releaseInfo)
}, idx, *client.host) }, idx, *client.host)
} }
return ng.Wait() return ng.Wait()

View file

@ -599,19 +599,21 @@ func (client *peerRESTClient) LoadGroup(group string) error {
} }
type serverUpdateInfo struct { type serverUpdateInfo struct {
URL *url.URL URL *url.URL
Sha256Sum []byte Sha256Sum []byte
Time time.Time Time time.Time
ReleaseInfo string
} }
// ServerUpdate - sends server update message to remote peers. // ServerUpdate - sends server update message to remote peers.
func (client *peerRESTClient) ServerUpdate(ctx context.Context, u *url.URL, sha256Sum []byte, lrTime time.Time) error { func (client *peerRESTClient) ServerUpdate(ctx context.Context, u *url.URL, sha256Sum []byte, lrTime time.Time, releaseInfo string) error {
values := make(url.Values) values := make(url.Values)
var reader bytes.Buffer var reader bytes.Buffer
if err := gob.NewEncoder(&reader).Encode(serverUpdateInfo{ if err := gob.NewEncoder(&reader).Encode(serverUpdateInfo{
URL: u, URL: u,
Sha256Sum: sha256Sum, Sha256Sum: sha256Sum,
Time: lrTime, Time: lrTime,
ReleaseInfo: releaseInfo,
}); err != nil { }); err != nil {
return err return err
} }

View file

@ -771,7 +771,7 @@ func (s *peerRESTServer) ServerUpdateHandler(w http.ResponseWriter, r *http.Requ
return return
} }
if _, err = updateServer(info.URL, info.Sha256Sum, info.Time, getMinioMode()); err != nil { if _, err = updateServer(info.URL, info.Sha256Sum, info.Time, info.ReleaseInfo, getMinioMode()); err != nil {
s.writeErrorResponse(w, err) s.writeErrorResponse(w, err)
return return
} }

View file

@ -1,5 +1,7 @@
// +build !fips
/* /*
* MinIO Cloud Storage, (C) 2015-2020 MinIO, Inc. * MinIO Cloud Storage, (C) 2015-2021 MinIO, Inc.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -369,7 +371,7 @@ func downloadReleaseURL(u *url.URL, timeout time.Duration, mode string) (content
// fbe246edbd382902db9a4035df7dce8cb441357d minio.RELEASE.2016-10-07T01-16-39Z.<hotfix_optional> // fbe246edbd382902db9a4035df7dce8cb441357d minio.RELEASE.2016-10-07T01-16-39Z.<hotfix_optional>
// //
// The second word must be `minio.` appended to a standard release tag. // The second word must be `minio.` appended to a standard release tag.
func parseReleaseData(data string) (sha256Sum []byte, releaseTime time.Time, err error) { func parseReleaseData(data string) (sha256Sum []byte, releaseTime time.Time, releaseInfo string, err error) {
defer func() { defer func() {
if err != nil { if err != nil {
err = AdminError{ err = AdminError{
@ -383,25 +385,25 @@ func parseReleaseData(data string) (sha256Sum []byte, releaseTime time.Time, err
fields := strings.Fields(data) fields := strings.Fields(data)
if len(fields) != 2 { if len(fields) != 2 {
err = fmt.Errorf("Unknown release data `%s`", data) err = fmt.Errorf("Unknown release data `%s`", data)
return sha256Sum, releaseTime, err return sha256Sum, releaseTime, releaseInfo, err
} }
sha256Sum, err = hex.DecodeString(fields[0]) sha256Sum, err = hex.DecodeString(fields[0])
if err != nil { if err != nil {
return sha256Sum, releaseTime, err return sha256Sum, releaseTime, releaseInfo, err
} }
releaseInfo := fields[1] releaseInfo = fields[1]
// Split release of style minio.RELEASE.2019-08-21T19-40-07Z.<hotfix> // Split release of style minio.RELEASE.2019-08-21T19-40-07Z.<hotfix>
nfields := strings.SplitN(releaseInfo, ".", 2) nfields := strings.SplitN(releaseInfo, ".", 2)
if len(nfields) != 2 { if len(nfields) != 2 {
err = fmt.Errorf("Unknown release information `%s`", releaseInfo) err = fmt.Errorf("Unknown release information `%s`", releaseInfo)
return sha256Sum, releaseTime, err return sha256Sum, releaseTime, releaseInfo, err
} }
if nfields[0] != "minio" { if nfields[0] != "minio" {
err = fmt.Errorf("Unknown release `%s`", releaseInfo) err = fmt.Errorf("Unknown release `%s`", releaseInfo)
return sha256Sum, releaseTime, err return sha256Sum, releaseTime, releaseInfo, err
} }
releaseTime, err = releaseTagToReleaseTime(nfields[1]) releaseTime, err = releaseTagToReleaseTime(nfields[1])
@ -409,7 +411,7 @@ func parseReleaseData(data string) (sha256Sum []byte, releaseTime time.Time, err
err = fmt.Errorf("Unknown release tag format. %w", err) err = fmt.Errorf("Unknown release tag format. %w", err)
} }
return sha256Sum, releaseTime, err return sha256Sum, releaseTime, releaseInfo, err
} }
func getUpdateTransport(timeout time.Duration) http.RoundTripper { func getUpdateTransport(timeout time.Duration) http.RoundTripper {
@ -433,7 +435,8 @@ func getLatestReleaseTime(u *url.URL, timeout time.Duration, mode string) (sha25
return sha256Sum, releaseTime, err return sha256Sum, releaseTime, err
} }
return parseReleaseData(data) sha256Sum, releaseTime, _, err = parseReleaseData(data)
return
} }
const ( const (
@ -516,7 +519,7 @@ func getUpdateReaderFromURL(u *url.URL, transport http.RoundTripper, mode string
return resp.Body, nil return resp.Body, nil
} }
func doUpdate(u *url.URL, lrTime time.Time, sha256Sum []byte, mode string) (err error) { func doUpdate(u *url.URL, lrTime time.Time, sha256Sum []byte, releaseInfo string, mode string) (err error) {
transport := getUpdateTransport(30 * time.Second) transport := getUpdateTransport(30 * time.Second)
var reader io.ReadCloser var reader io.ReadCloser
if u.Scheme == "https" || u.Scheme == "http" { if u.Scheme == "https" || u.Scheme == "http" {
@ -539,7 +542,7 @@ func doUpdate(u *url.URL, lrTime time.Time, sha256Sum []byte, mode string) (err
minisignPubkey := env.Get(envMinisignPubKey, "") minisignPubkey := env.Get(envMinisignPubKey, "")
if minisignPubkey != "" { if minisignPubkey != "" {
v := selfupdate.NewVerifier() v := selfupdate.NewVerifier()
u.Path = path.Dir(u.Path) + slashSeparator + "minio.RELEASE." + lrTime.Format(minioReleaseTagTimeLayout) + ".minisig" u.Path = path.Dir(u.Path) + slashSeparator + releaseInfo + ".minisig"
if err = v.LoadFromURL(u.String(), minisignPubkey, transport); err != nil { if err = v.LoadFromURL(u.String(), minisignPubkey, transport); err != nil {
return AdminError{ return AdminError{
Code: AdminUpdateApplyFailure, Code: AdminUpdateApplyFailure,

24
cmd/update_fips.go Normal file
View file

@ -0,0 +1,24 @@
// +build fips
/*
* MinIO Cloud Storage, (C) 2021 MinIO, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cmd
var (
// Newer official download info URLs appear earlier below.
minioReleaseInfoURL = minioReleaseURL + "minio.fips.sha256sum"
)

View file

@ -298,22 +298,25 @@ func TestDownloadReleaseData(t *testing.T) {
func TestParseReleaseData(t *testing.T) { func TestParseReleaseData(t *testing.T) {
releaseTime, _ := releaseTagToReleaseTime("RELEASE.2016-10-07T01-16-39Z") releaseTime, _ := releaseTagToReleaseTime("RELEASE.2016-10-07T01-16-39Z")
testCases := []struct { testCases := []struct {
data string data string
expectedResult time.Time expectedResult time.Time
expectedSha256hex string expectedSha256hex string
expectedErr bool expectedReleaseInfo string
expectedErr bool
}{ }{
{"more than two fields", time.Time{}, "", true}, {"more than two fields", time.Time{}, "", "", true},
{"more than", time.Time{}, "", true}, {"more than", time.Time{}, "", "", true},
{"more than.two.fields", time.Time{}, "", true}, {"more than.two.fields", time.Time{}, "", "", true},
{"more minio.RELEASE.fields", time.Time{}, "", true}, {"more minio.RELEASE.fields", time.Time{}, "", "", true},
{"more minio.RELEASE.2016-10-07T01-16-39Z", time.Time{}, "", true}, {"more minio.RELEASE.2016-10-07T01-16-39Z", time.Time{}, "", "", true},
{"fbe246edbd382902db9a4035df7dce8cb441357d minio.RELEASE.2016-10-07T01-16-39Z\n", releaseTime, "fbe246edbd382902db9a4035df7dce8cb441357d", false}, {"fbe246edbd382902db9a4035df7dce8cb441357d minio.RELEASE.2016-10-07T01-16-39Z\n", releaseTime, "fbe246edbd382902db9a4035df7dce8cb441357d",
{"fbe246edbd382902db9a4035df7dce8cb441357d minio.RELEASE.2016-10-07T01-16-39Z.customer-hotfix\n", releaseTime, "fbe246edbd382902db9a4035df7dce8cb441357d", false}, "minio.RELEASE.2016-10-07T01-16-39Z", false},
{"fbe246edbd382902db9a4035df7dce8cb441357d minio.RELEASE.2016-10-07T01-16-39Z.customer-hotfix\n", releaseTime, "fbe246edbd382902db9a4035df7dce8cb441357d",
"minio.RELEASE.2016-10-07T01-16-39Z.customer-hotfix", false},
} }
for i, testCase := range testCases { for i, testCase := range testCases {
sha256Sum, result, err := parseReleaseData(testCase.data) sha256Sum, result, releaseInfo, err := parseReleaseData(testCase.data)
if !testCase.expectedErr { if !testCase.expectedErr {
if err != nil { if err != nil {
t.Errorf("error case %d: expected no error, got: %v", i+1, err) t.Errorf("error case %d: expected no error, got: %v", i+1, err)
@ -328,6 +331,9 @@ func TestParseReleaseData(t *testing.T) {
if !testCase.expectedResult.Equal(result) { if !testCase.expectedResult.Equal(result) {
t.Errorf("case %d: result: expected: %v, got: %v", i+1, testCase.expectedResult, result) t.Errorf("case %d: result: expected: %v, got: %v", i+1, testCase.expectedResult, result)
} }
if testCase.expectedReleaseInfo != releaseInfo {
t.Errorf("case %d: result: expected: %v, got: %v", i+1, testCase.expectedReleaseInfo, releaseInfo)
}
} }
} }
} }