From 641e564b6572d70ab3e765732073cb6a59872527 Mon Sep 17 00:00:00 2001 From: Harshavardhana Date: Thu, 8 Apr 2021 09:51:11 -0700 Subject: [PATCH] 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. --- cmd/admin-handlers.go | 13 ++++++------- cmd/notification.go | 4 ++-- cmd/peer-rest-client.go | 16 +++++++++------- cmd/peer-rest-server.go | 2 +- cmd/update.go | 25 ++++++++++++++----------- cmd/update_fips.go | 24 ++++++++++++++++++++++++ cmd/update_test.go | 30 ++++++++++++++++++------------ 7 files changed, 74 insertions(+), 40 deletions(-) create mode 100644 cmd/update_fips.go diff --git a/cmd/admin-handlers.go b/cmd/admin-handlers.go index 7b61a3e82..d30abbc01 100644 --- a/cmd/admin-handlers.go +++ b/cmd/admin-handlers.go @@ -64,8 +64,8 @@ const ( mgmtForceStop = "forceStop" ) -func updateServer(u *url.URL, sha256Sum []byte, lrTime time.Time, mode string) (us madmin.ServerUpdateStatus, err error) { - if err = doUpdate(u, lrTime, sha256Sum, mode); err != nil { +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, releaseInfo, mode); err != nil { return us, err } @@ -115,14 +115,13 @@ func (a adminAPIHandlers) ServerUpdateHandler(w http.ResponseWriter, r *http.Req return } - sha256Sum, lrTime, err := parseReleaseData(content) + sha256Sum, lrTime, releaseInfo, err := parseReleaseData(content) if err != nil { writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) return } - u.Path = path.Dir(u.Path) + SlashSeparator + "minio.RELEASE." + lrTime.Format(minioReleaseTagTimeLayout) - + u.Path = path.Dir(u.Path) + SlashSeparator + releaseInfo crTime, err := GetCurrentReleaseTime() if err != nil { writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) @@ -146,7 +145,7 @@ func (a adminAPIHandlers) ServerUpdateHandler(w http.ResponseWriter, r *http.Req return } - for _, nerr := range globalNotificationSys.ServerUpdate(ctx, u, sha256Sum, lrTime) { + for _, nerr := range globalNotificationSys.ServerUpdate(ctx, u, sha256Sum, lrTime, releaseInfo) { if nerr.Err != nil { logger.GetReqInfo(ctx).SetTags("peerAddress", nerr.Host.String()) 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 { 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) diff --git a/cmd/notification.go b/cmd/notification.go index 998315774..3c56fac04 100644 --- a/cmd/notification.go +++ b/cmd/notification.go @@ -400,7 +400,7 @@ func (sys *NotificationSys) DownloadProfilingData(ctx context.Context, writer io } // 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)) for idx, client := range sys.peerClients { if client == nil { @@ -408,7 +408,7 @@ func (sys *NotificationSys) ServerUpdate(ctx context.Context, u *url.URL, sha256 } client := client ng.Go(ctx, func() error { - return client.ServerUpdate(ctx, u, sha256Sum, lrTime) + return client.ServerUpdate(ctx, u, sha256Sum, lrTime, releaseInfo) }, idx, *client.host) } return ng.Wait() diff --git a/cmd/peer-rest-client.go b/cmd/peer-rest-client.go index adec89215..7f2f396c5 100644 --- a/cmd/peer-rest-client.go +++ b/cmd/peer-rest-client.go @@ -599,19 +599,21 @@ func (client *peerRESTClient) LoadGroup(group string) error { } type serverUpdateInfo struct { - URL *url.URL - Sha256Sum []byte - Time time.Time + URL *url.URL + Sha256Sum []byte + Time time.Time + ReleaseInfo string } // 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) var reader bytes.Buffer if err := gob.NewEncoder(&reader).Encode(serverUpdateInfo{ - URL: u, - Sha256Sum: sha256Sum, - Time: lrTime, + URL: u, + Sha256Sum: sha256Sum, + Time: lrTime, + ReleaseInfo: releaseInfo, }); err != nil { return err } diff --git a/cmd/peer-rest-server.go b/cmd/peer-rest-server.go index 2372a9734..9de9c497d 100644 --- a/cmd/peer-rest-server.go +++ b/cmd/peer-rest-server.go @@ -771,7 +771,7 @@ func (s *peerRESTServer) ServerUpdateHandler(w http.ResponseWriter, r *http.Requ 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) return } diff --git a/cmd/update.go b/cmd/update.go index fd79ce094..f9fe982de 100644 --- a/cmd/update.go +++ b/cmd/update.go @@ -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"); * 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. // // 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() { if err != nil { err = AdminError{ @@ -383,25 +385,25 @@ func parseReleaseData(data string) (sha256Sum []byte, releaseTime time.Time, err fields := strings.Fields(data) if len(fields) != 2 { err = fmt.Errorf("Unknown release data `%s`", data) - return sha256Sum, releaseTime, err + return sha256Sum, releaseTime, releaseInfo, err } sha256Sum, err = hex.DecodeString(fields[0]) 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. nfields := strings.SplitN(releaseInfo, ".", 2) if len(nfields) != 2 { err = fmt.Errorf("Unknown release information `%s`", releaseInfo) - return sha256Sum, releaseTime, err + return sha256Sum, releaseTime, releaseInfo, err } if nfields[0] != "minio" { err = fmt.Errorf("Unknown release `%s`", releaseInfo) - return sha256Sum, releaseTime, err + return sha256Sum, releaseTime, releaseInfo, err } 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) } - return sha256Sum, releaseTime, err + return sha256Sum, releaseTime, releaseInfo, err } 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 parseReleaseData(data) + sha256Sum, releaseTime, _, err = parseReleaseData(data) + return } const ( @@ -516,7 +519,7 @@ func getUpdateReaderFromURL(u *url.URL, transport http.RoundTripper, mode string 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) var reader io.ReadCloser 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, "") if minisignPubkey != "" { 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 { return AdminError{ Code: AdminUpdateApplyFailure, diff --git a/cmd/update_fips.go b/cmd/update_fips.go new file mode 100644 index 000000000..e1c136239 --- /dev/null +++ b/cmd/update_fips.go @@ -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" +) diff --git a/cmd/update_test.go b/cmd/update_test.go index 0855df08c..17aa81373 100644 --- a/cmd/update_test.go +++ b/cmd/update_test.go @@ -298,22 +298,25 @@ func TestDownloadReleaseData(t *testing.T) { func TestParseReleaseData(t *testing.T) { releaseTime, _ := releaseTagToReleaseTime("RELEASE.2016-10-07T01-16-39Z") testCases := []struct { - data string - expectedResult time.Time - expectedSha256hex string - expectedErr bool + data string + expectedResult time.Time + expectedSha256hex string + expectedReleaseInfo string + expectedErr bool }{ - {"more than two fields", time.Time{}, "", true}, - {"more than", time.Time{}, "", true}, - {"more than.two.fields", time.Time{}, "", true}, - {"more minio.RELEASE.fields", 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.customer-hotfix\n", releaseTime, "fbe246edbd382902db9a4035df7dce8cb441357d", false}, + {"more than two fields", time.Time{}, "", "", true}, + {"more than", time.Time{}, "", "", true}, + {"more than.two.fields", time.Time{}, "", "", true}, + {"more minio.RELEASE.fields", 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", + "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 { - sha256Sum, result, err := parseReleaseData(testCase.data) + sha256Sum, result, releaseInfo, err := parseReleaseData(testCase.data) if !testCase.expectedErr { if err != nil { 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) { 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) + } } } }