Skip to content

Commit

Permalink
Merge pull request #614 from nnmin-aws/nnmin-rel
Browse files Browse the repository at this point in the history
Prepare new release
  • Loading branch information
k8s-ci-robot committed Jul 25, 2023
2 parents 0f53431 + d7f4910 commit 53b6ca2
Show file tree
Hide file tree
Showing 15 changed files with 644 additions and 242 deletions.
3 changes: 1 addition & 2 deletions Makefile
Expand Up @@ -7,7 +7,6 @@ VERSION ?= $(shell $(shell pwd)/hack/get-version.sh)
GOOS ?= $(shell go env GOOS)
GOARCH ?= $(shell go env GOARCH)
GOPROXY ?= $(shell go env GOPROXY)
SOURCES := $(shell find . -name '*.go')
GIT_COMMIT ?= $(shell git rev-parse HEAD)
BUILD_DATE ?= $(shell date -u +"%Y-%m-%dT%H:%M:%SZ")
BUILD_DATE_STRIPPED := $(subst -,,$(subst :,,$(BUILD_DATE)))
Expand Down Expand Up @@ -55,7 +54,7 @@ $(CHECKSUM_FILE): build-all-bins
@echo $(ALL_BIN_TARGETS)
$(foreach target,$(ALL_BIN_TARGETS),$(call checksum,$(target),$(CHECKSUM_FILE)))

$(OUTPUT)/bin/%: $(SOURCES)
$(OUTPUT)/bin/%:
GO111MODULE=on \
CGO_ENABLED=0 \
GOOS=$(GOOS) \
Expand Down
2 changes: 2 additions & 0 deletions cmd/aws-iam-authenticator/root.go
Expand Up @@ -108,6 +108,8 @@ func getConfig() (config.Config, error) {
DynamicFilePath: viper.GetString("server.dynamicfilepath"),
//DynamicFileUserIDStrict: if true, then aws UserId from sts will be used to look up the roleMapping/userMapping; or aws IdentityArn is used
DynamicFileUserIDStrict: viper.GetBool("server.dynamicfileUserIDStrict"),
//DynamicBackendModePath: the file path containing the backend mode
DynamicBackendModePath: viper.GetString("server.dynamicBackendModePath"),
}
if err := viper.UnmarshalKey("server.mapRoles", &cfg.RoleMappings); err != nil {
return cfg, fmt.Errorf("invalid server role mappings: %v", err)
Expand Down
1 change: 1 addition & 0 deletions hack/dev/authenticator_with_dynamicfile_mode.yaml
Expand Up @@ -7,6 +7,7 @@ server:
kubeconfig: {{AUTHENTICATOR_KUBECONFIG}}
backendmode: [ "MountedFile", "DynamicFile" ]
dynamicfilepath: {{AUTHENTICATOR_DYNAMICFILE_PATH}}
dynamicBackendModePath: {{BACKENDMODE_PATH}}
reservedPrefixConfig:
- backendmode: DynamicFile
usernamePrefixReserveList:
Expand Down
96 changes: 88 additions & 8 deletions hack/e2e-dynamicfile.sh
Expand Up @@ -31,7 +31,9 @@ policies_json="${OUTPUT}/dev/authenticator/policies.json"
allow_assume_role_policies_template="${REPO_ROOT}/hack/dev/allow_assume_role_policy.template"
allow_assume_role_policies_json="${OUTPUT}/dev/authenticator/allow_assume_role_policy.json"
access_entry_tmp="${OUTPUT}/dev/authenticator/access-entry/access-entries.tmp"
access_entry_user_tmp="${OUTPUT}/dev/authenticator/access-entry/access-entries-user.tmp"
access_entry_json="${OUTPUT}/dev/authenticator/access-entry/access-entries.json"
backend_mode_json="${OUTPUT}/dev/authenticator/access-entry/backend-modes.json"
client_dir="${OUTPUT}/dev/client"
kubectl_kubeconfig="${client_dir}/kubeconfig.yaml"

Expand All @@ -56,6 +58,13 @@ function e2e_mountfile() {
}

function e2e_dynamicfile_username_prefix_enforce(){
cat << EOF > ${backend_mode_json}
{
"backendMode": "MountedFile DynamicFile"
}
EOF

sleep 20
set +e
RoleOutput=$(aws iam get-role --role-name ${USERNAME_TEST_ROLE} 2>/dev/null)

Expand Down Expand Up @@ -112,8 +121,8 @@ function e2e_dynamicfile_username_prefix_enforce(){
sed -e "s|{{AWS_ACCOUNT}}|${AWS_ACCOUNT}|g" \
-e "s|{{USERNAME_TEST_ROLE}}|${USERNAME_TEST_ROLE}|g" \
-e "s|{{USER_ID}}|${USERID}|g" \
"${access_entry_username_prefix_template}" > "${access_entry_tmp}"
mv "${access_entry_tmp}" "${access_entry_json}"
"${access_entry_username_prefix_template}" > "${access_entry_user_tmp}"
mv "${access_entry_user_tmp}" "${access_entry_json}"
#sleep 10 seconds to make access entry effective
sleep 10
set +e
Expand All @@ -128,6 +137,12 @@ function e2e_dynamicfile_username_prefix_enforce(){
}

function e2e_dynamicfile(){
cat << EOF > "${backend_mode_json}"
{
"backendMode": "MountedFile DynamicFile"
}
EOF
sleep 20
set +e
RoleOutput=$(aws iam get-role --role-name authenticator-dev-cluster-testrole 2>/dev/null)

Expand Down Expand Up @@ -216,14 +231,79 @@ function e2e_dynamicfile(){
unset AWS_ACCESS_KEY_ID AWS_SECRET_ACCESS_KEY AWS_SESSION_TOKEN
}

echo "start end to end testing for mountfile mode"
e2e_mountfile
echo "starting end to end testing for dynamicfile mode"
e2e_dynamicfile
echo "starting end to end testing for dynamicfile mode with username prefix"
e2e_dynamicfile_username_prefix_enforce
function e2e_dynamic_backend_mode(){

# set backend mode to MOUNTEDFILE only
sed -e "s|{{AWS_ACCOUNT}}|${AWS_ACCOUNT}|g" \
-e "s|{{AWS_TEST_ROLE}}|${AWS_TEST_ROLE}|g" \
-e "s|{{USER_ID}}|${USERID}|g" \
"${access_entry_template}" > "${access_entry_tmp}"
mv "${access_entry_tmp}" "${access_entry_json}"
cat << EOF > "${backend_mode_json}"
{
"backendMode": "MountedFile"
}
EOF
sleep 20

set -e
OUT=$(aws sts assume-role --role-arn arn:aws:iam::${AWS_ACCOUNT}:role/${AWS_TEST_ROLE} --role-session-name aaa);\
export AWS_ACCESS_KEY_ID=$(echo $OUT | jq -r '.Credentials''.AccessKeyId');\
export AWS_SECRET_ACCESS_KEY=$(echo $OUT | jq -r '.Credentials''.SecretAccessKey');\
export AWS_SESSION_TOKEN=$(echo $OUT | jq -r '.Credentials''.SessionToken');

OUT=$(aws sts get-caller-identity)
echo "current role: "$OUT
if [ -z "$OUT" ]
then
echo "can't assume-role: ""${AWS_TEST_ROLE}"
exit 1
fi

set +e
OUT=$(kubectl --kubeconfig=${kubectl_kubeconfig} --context="test-authenticator" get nodes 2>/var/tmp/err.txt)
echo $OUT
if grep -q "Unauthorized" "/var/tmp/err.txt"; then
echo -n ""
else
echo "end to end testing for dynamic backend mode failed"
exit 1
fi

# set backend mode to MOUNTEDFILE,DYNAMICFILE
cat << EOF > "${backend_mode_json}"
{
"backendMode": "MountedFile DynamicFile"
}
EOF
sleep 20

OUT=$(aws sts get-caller-identity)
echo "current role: "$OUT
if [ -z "$OUT" ]
then
echo "can't assume-role: ""${AWS_TEST_ROLE}"
exit 1
fi

OUT=$(kubectl --kubeconfig=${kubectl_kubeconfig} --context="test-authenticator" get nodes|grep Ready)
if [ ! -z "$OUT" ]
then
echo $OUT
echo "end to end testing for dynamic backend mode succeeded"

else
echo "end to end testing for dynamic backend mode failed"
exit 1
fi
unset AWS_ACCESS_KEY_ID AWS_SECRET_ACCESS_KEY AWS_SESSION_TOKEN
}

echo "start end to end testing for mountfile mode"
e2e_mountfile
echo "starting end to end testing for dynamicfile mode"
e2e_dynamicfile
echo "starting end to end testing for dynamic backend mode"
e2e_dynamic_backend_mode
echo "starting end to end testing for dynamicfile mode with username prefix"
e2e_dynamicfile_username_prefix_enforce
3 changes: 2 additions & 1 deletion hack/lib/dev-env.sh
Expand Up @@ -67,6 +67,7 @@ authenticator_dynamicfile_host_path="${OUTPUT}/dev/authenticator/access-entry"
authenticator_access_entry_host_file="${authenticator_dynamicfile_host_path}/access-entries.json"
authenticator_dynamicfile_dest_path="/var/authenticator/access-entry"
authenticator_access_entry_dest_file="${authenticator_dynamicfile_dest_path}/access-entries.json"
authenticator_backend_mode_dest_file="${authenticator_dynamicfile_dest_path}/backend-modes.json"
authenticator_config_dest_dir="/etc/authenticator"
authenticator_export_dest_dir="/var/authenticator/export"
authenticator_state_dest_dir="/var/authenticator/state"
Expand Down Expand Up @@ -145,6 +146,7 @@ function write_authenticator_with_dynamicfile_mode_config() {
-e "s|{{AUTHENTICATOR_IP}}|${AUTHENTICATOR_IP}|g" \
-e "s|{{CLUSTER_NAME}}|${CLUSTER_NAME}|g" \
-e "s|{{AUTHENTICATOR_DYNAMICFILE_PATH}}|${authenticator_access_entry_dest_file}|g" \
-e "s|{{BACKENDMODE_PATH}}|${authenticator_backend_mode_dest_file}|g" \
"${authenticator_dynamicfile_mode_config_template}" > "${authenticator_dynamicfile_mode_config}"
cat "${authenticator_dynamicfile_mode_config}"
cp "${authenticator_access_entry_template}" "${authenticator_access_entry_host_file}"
Expand Down Expand Up @@ -200,7 +202,6 @@ function start_authenticator_with_dynamicfile() {
--publish ${authenticator_healthz_port}:${authenticator_healthz_port} \
--publish ${AUTHENTICATOR_PORT}:${AUTHENTICATOR_PORT} \
--env AWS_REGION="us-west-2" \
--rm \
"${AUTHENTICATOR_IMAGE}" \
server \
--config "${authenticator_config_dest_dir}/authenticator_dynamicfile_mode.yaml"
Expand Down
2 changes: 2 additions & 0 deletions pkg/config/types.go
Expand Up @@ -154,6 +154,8 @@ type Config struct {
DynamicFileUserIDStrict bool
// ReservedPrefixConfig defines reserved username prefixes for each backend
ReservedPrefixConfig map[string]ReservedPrefixConfig
// Dynamic File Path for BackendMode
DynamicBackendModePath string
}

type ReservedPrefixConfig struct {
Expand Down
106 changes: 106 additions & 0 deletions pkg/fileutil/util.go
@@ -0,0 +1,106 @@
package fileutil

import (
"os"
"time"

"github.com/fsnotify/fsnotify"
"github.com/sirupsen/logrus"
"k8s.io/apimachinery/pkg/util/wait"
"sigs.k8s.io/aws-iam-authenticator/pkg/metrics"
)

type FileChangeCallBack interface {
CallBackForFileLoad(dynamicContent []byte) error
CallBackForFileDeletion() error
}

func waitUntilFileAvailable(filename string, stopCh <-chan struct{}) {
if _, err := os.Stat(filename); err == nil {
return
}
ticker := time.NewTicker(1 * time.Second)
defer ticker.Stop()
for {
select {
case <-stopCh:
logrus.Infof("startLoadDynamicFile: waitUntilFileAvailable exit because get stopCh, filename is %s", filename)
return
case <-ticker.C:
if _, err := os.Stat(filename); err == nil {
return
}
}
}
}

func loadDynamicFile(filename string, stopCh <-chan struct{}) ([]byte, error) {
waitUntilFileAvailable(filename, stopCh)
if content, err := os.ReadFile(filename); err == nil {
logrus.Infof("LoadDynamicFile: %v is available. content is %s", filename, string(content))
return content, nil
} else {
return nil, err
}
}

func StartLoadDynamicFile(filename string, callBack FileChangeCallBack, stopCh <-chan struct{}) {
go wait.Until(func() {
// start to watch the file change
watcher, err := fsnotify.NewWatcher()
if err != nil {
logrus.Errorf("startLoadDynamicFile: failed when call fsnotify.NewWatcher, %+v", err)
metrics.Get().DynamicFileFailures.Inc()
return
}
defer watcher.Close()
content, err := loadDynamicFile(filename, stopCh)
if err != nil {
return
}
err = watcher.Add(filename)
if err != nil {
logrus.Errorf("startLoadDynamicFile: could not add file to watcher %v", err)
metrics.Get().DynamicFileFailures.Inc()
return
}
if err := callBack.CallBackForFileLoad(content); err != nil {
logrus.Errorf("StartLoadDynamicFile: error in callBackForFileLoad, %v", err)
}
for {
select {
case <-stopCh:
logrus.Infof("startLoadDynamicFile: watching exit because stopCh closed, filename is %s", filename)
return
case event := <-watcher.Events:
switch {
case event.Op&fsnotify.Write == fsnotify.Write, event.Op&fsnotify.Create == fsnotify.Create:
// reload the access entry file
logrus.Info("startLoadDynamicFile: got WRITE/CREATE event reload it the memory")
content, err := loadDynamicFile(filename, stopCh)
if err != nil {
logrus.Errorf("StartLoadDynamicFile: error in loadDynamicFile, %v", err)
return
}
if err := callBack.CallBackForFileLoad(content); err != nil {
logrus.Errorf("StartLoadDynamicFile: error in callBackForFileLoad, %v", err)
}
case event.Op&fsnotify.Rename == fsnotify.Rename, event.Op&fsnotify.Remove == fsnotify.Remove:
logrus.Info("startLoadDynamicFile: got RENAME/REMOVE event")
// test if the "REMOVE" is triggered by vi or cp cmd
_, err := os.Stat(filename)
if os.IsNotExist(err) {
if err := callBack.CallBackForFileDeletion(); err != nil {
logrus.Errorf("StartLoadDynamicFile: error in callBackForFileDeletion, %v", err)
}
}
return
}
case err := <-watcher.Errors:
logrus.Errorf("startLoadDynamicFile: watcher.Errors for dynamic file %v", err)
metrics.Get().DynamicFileFailures.Inc()
return
}
}
}, time.Second, stopCh)
}

0 comments on commit 53b6ca2

Please sign in to comment.